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

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

Issue 2320403002: Update reading list entry on download (Closed)
Patch Set: 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 std::string title,
71 SuccessState success) {
74 DCHECK(working_); 72 DCHECK(working_);
75 download_completion_.Run(url, success); 73
76 distiller_.reset(); 74 auto postDelete = base::Bind(
sdefresne 2016/09/09 09:58:57 style: variable should name should use name_with_u
lody 2016/09/09 12:17:53 Done.
77 working_ = false; 75 [](URLDownloader* _this, const GURL& url, std::string title,
78 HandleNextTask(); 76 SuccessState success) {
77 _this->download_completion_.Run(
78 url, success,
79 GURL("file://" + _this->OfflineURLPagePath(url).value()), title);
sdefresne 2016/09/09 09:58:57 nit: maybe use url::kFileScheme instead of "file"
lody 2016/09/09 12:17:53 Done.
80 _this->distiller_.reset();
81 _this->working_ = false;
82 _this->HandleNextTask();
83 },
84 base::Unretained(this), url, title, success);
noyau (Ping after 24h) 2016/09/09 09:39:58 I'm always worried when I see a base::Unretained.
sdefresne 2016/09/09 09:58:57 +1
lody 2016/09/09 12:17:53 That's what the task_tracker_ is for. Already had
noyau (Ping after 24h) 2016/09/09 12:45:22 Ah, yes, I remember now. Sorry, should have checke
85
86 // If downloading failed, clean up any partial download.
87 if (success == ERROR_RETRY || success == ERROR_PERMANENT) {
88 task_tracker_.PostTaskAndReply(
89 web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(),
90 FROM_HERE, base::Bind(
91 [](base::FilePath offlineDirectoryPath) {
sdefresne 2016/09/09 09:58:57 style: variable should name should use name_with_u
lody 2016/09/09 12:17:53 Done.
92 base::DeleteFile(offlineDirectoryPath, true);
93 },
94 OfflineURLDirectoryPath(url)),
95 postDelete);
96 } else {
97 postDelete.Run();
98 }
79 } 99 }
80 100
81 void URLDownloader::DeleteCompletionHandler(const GURL& url, bool success) { 101 void URLDownloader::DeleteCompletionHandler(const GURL& url, bool success) {
82 DCHECK(working_); 102 DCHECK(working_);
83 delete_completion_.Run(url, success); 103 delete_completion_.Run(url, success);
84 working_ = false; 104 working_ = false;
85 HandleNextTask(); 105 HandleNextTask();
86 } 106 }
87 107
88 void URLDownloader::HandleNextTask() { 108 void URLDownloader::HandleNextTask() {
(...skipping 15 matching lines...) Expand all
104 base::Unretained(this), url)); 124 base::Unretained(this), url));
105 } else if (task.first == DOWNLOAD) { 125 } else if (task.first == DOWNLOAD) {
106 DCHECK(!distiller_); 126 DCHECK(!distiller_);
107 OfflineURLExists(url, base::Bind(&URLDownloader::DownloadURL, 127 OfflineURLExists(url, base::Bind(&URLDownloader::DownloadURL,
108 base::Unretained(this), url)); 128 base::Unretained(this), url));
109 } 129 }
110 } 130 }
111 131
112 void URLDownloader::DownloadURL(GURL url, bool offlineURLExists) { 132 void URLDownloader::DownloadURL(GURL url, bool offlineURLExists) {
113 if (offlineURLExists) { 133 if (offlineURLExists) {
114 DownloadCompletionHandler(url, false); 134 DownloadCompletionHandler(url, "", DOWNLOAD_EXISTS);
115 return; 135 return;
116 } 136 }
117 137
118 distiller_.reset(new dom_distiller::DistillerViewer( 138 distiller_.reset(new dom_distiller::DistillerViewer(
119 distiller_service_, pref_service_, url, 139 distiller_service_, pref_service_, url,
120 base::Bind(&URLDownloader::DistillerCallback, base::Unretained(this)))); 140 base::Bind(&URLDownloader::DistillerCallback, base::Unretained(this))));
121 } 141 }
122 142
123 void URLDownloader::DistillerCallback( 143 void URLDownloader::DistillerCallback(
124 const GURL& pageURL, 144 const GURL& pageURL,
125 const std::string& html, 145 const std::string& html,
126 const std::vector<dom_distiller::DistillerViewerInterface::ImageInfo>& 146 const std::vector<dom_distiller::DistillerViewerInterface::ImageInfo>&
127 images) { 147 images,
148 const std::string& title) {
128 std::vector<dom_distiller::DistillerViewer::ImageInfo> imagesBlock = images; 149 std::vector<dom_distiller::DistillerViewer::ImageInfo> imagesBlock = images;
129 std::string blockHTML = html; 150 std::string blockHTML = html;
151 if (html.empty()) {
152 // TODO identify retry from permanent errors
153 DownloadCompletionHandler(pageURL, "", ERROR_PERMANENT);
154 return;
155 }
130 task_tracker_.PostTaskAndReplyWithResult( 156 task_tracker_.PostTaskAndReplyWithResult(
131 web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(), 157 web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE).get(),
132 FROM_HERE, 158 FROM_HERE,
133 base::Bind(&URLDownloader::SaveDistilledHTML, base::Unretained(this), 159 base::Bind(&URLDownloader::SaveDistilledHTML, base::Unretained(this),
134 pageURL, imagesBlock, blockHTML), 160 pageURL, imagesBlock, blockHTML),
135 base::Bind(&URLDownloader::DownloadCompletionHandler, 161 base::Bind(&URLDownloader::DownloadCompletionHandler,
136 base::Unretained(this), pageURL)); 162 base::Unretained(this), pageURL, title));
137 } 163 }
138 164
139 bool URLDownloader::SaveDistilledHTML( 165 URLDownloader::SuccessState URLDownloader::SaveDistilledHTML(
140 const GURL& url, 166 const GURL& url,
141 std::vector<dom_distiller::DistillerViewerInterface::ImageInfo> images, 167 std::vector<dom_distiller::DistillerViewerInterface::ImageInfo> images,
142 std::string html) { 168 std::string html) {
143 if (CreateOfflineURLDirectory(url)) { 169 if (CreateOfflineURLDirectory(url)) {
144 return SaveHTMLForURL(SaveAndReplaceImagesInHTML(url, html, images), url); 170 return SaveHTMLForURL(SaveAndReplaceImagesInHTML(url, html, images), url)
171 ? DOWNLOAD_SUCCESS
172 : ERROR_PERMANENT;
145 } 173 }
146 return false; 174 return ERROR_PERMANENT;
147 } 175 }
148 176
149 base::FilePath URLDownloader::OfflineDirectoryPath() { 177 base::FilePath URLDownloader::OfflineDirectoryPath() {
150 return base_directory_.Append(kOfflineDirectory); 178 return base_directory_.Append(kOfflineDirectory);
151 } 179 }
152 180
153 base::FilePath URLDownloader::OfflineURLDirectoryPath(const GURL& url) { 181 base::FilePath URLDownloader::OfflineURLDirectoryPath(const GURL& url) {
154 std::string hash = base::MD5String(url.spec()); 182 std::string hash = base::MD5String(url.spec());
155 return OfflineDirectoryPath().Append(hash); 183 return OfflineDirectoryPath().Append(hash);
156 } 184 }
157 185
158 base::FilePath URLDownloader::OfflineURLPagePath(const GURL& url) { 186 base::FilePath URLDownloader::OfflineURLPagePath(const GURL& url) {
159 return OfflineURLDirectoryPath(url).Append("page.html"); 187 return OfflineURLDirectoryPath(url).Append("page.html");
160 } 188 }
161 189
162 bool URLDownloader::CreateOfflineURLDirectory(const GURL& url) { 190 bool URLDownloader::CreateOfflineURLDirectory(const GURL& url) {
163 base::FilePath path = OfflineURLDirectoryPath(url); 191 base::FilePath path = OfflineURLDirectoryPath(url);
164 if (!DirectoryExists(path)) { 192 if (!DirectoryExists(path)) {
165 return CreateDirectoryAndGetError(path, nil); 193 return CreateDirectoryAndGetError(path, nil);
166 } 194 }
167 return true; 195 return true;
168 } 196 }
169 197
170 std::string URLDownloader::SaveImage(const GURL& url, 198 bool URLDownloader::SaveImage(const GURL& url,
171 const GURL& imageURL, 199 const GURL& imageURL,
172 const std::string& data) { 200 const std::string& data,
173 base::FilePath path = 201 base::FilePath& path) {
174 OfflineURLDirectoryPath(url).Append(base::MD5String(imageURL.spec())); 202 path = OfflineURLDirectoryPath(url).Append(base::MD5String(imageURL.spec()));
175 if (!base::PathExists(path)) { 203 if (!base::PathExists(path)) {
176 base::WriteFile(path, data.c_str(), data.length()); 204 return base::WriteFile(path, data.c_str(), data.length()) > 0;
177 } 205 }
178 return path.AsUTF8Unsafe(); 206 return true;
179 } 207 }
180 208
181 // TODO(crbug.com/625621) DomDistiller doesn't correctly handle srcset
182 // attributes in img tags.
183 std::string URLDownloader::SaveAndReplaceImagesInHTML( 209 std::string URLDownloader::SaveAndReplaceImagesInHTML(
184 const GURL& url, 210 const GURL& url,
185 const std::string& html, 211 const std::string& html,
186 const std::vector<dom_distiller::DistillerViewerInterface::ImageInfo>& 212 const std::vector<dom_distiller::DistillerViewerInterface::ImageInfo>&
187 images) { 213 images) {
188 std::string mutableHTML = html; 214 std::string mutableHTML = html;
189 for (size_t i = 0; i < images.size(); i++) { 215 for (size_t i = 0; i < images.size(); i++) {
190 const std::string& localImagePath = 216 base::FilePath localImagePath;
sdefresne 2016/09/09 09:58:58 style: s/localImagePath/local_image_path/
lody 2016/09/09 12:17:53 Done.
191 SaveImage(url, images[i].url, images[i].data); 217 if (!SaveImage(url, images[i].url, images[i].data, localImagePath)) {
218 return "";
sdefresne 2016/09/09 09:58:58 Please prefer to use std::string() instead of "".
lody 2016/09/09 12:17:53 Done.
219 }
192 const std::string& imageURL = images[i].url.spec(); 220 const std::string& imageURL = images[i].url.spec();
193 size_t imageURLSize = imageURL.size(); 221 size_t imageURLSize = imageURL.size();
194 size_t pos = mutableHTML.find(imageURL, 0); 222 size_t pos = mutableHTML.find(imageURL, 0);
195 while (pos != std::string::npos) { 223 while (pos != std::string::npos) {
196 mutableHTML.replace(pos, imageURLSize, localImagePath); 224 mutableHTML.replace(pos, imageURLSize, localImagePath.AsUTF8Unsafe());
197 pos = mutableHTML.find(imageURL, pos + imageURLSize); 225 pos = mutableHTML.find(imageURL, pos + imageURLSize);
198 } 226 }
199 } 227 }
200 return mutableHTML; 228 return mutableHTML;
201 } 229 }
202 230
203 bool URLDownloader::SaveHTMLForURL(std::string html, const GURL& url) { 231 bool URLDownloader::SaveHTMLForURL(std::string html, const GURL& url) {
232 if (html.empty()) {
233 return false;
234 }
204 base::FilePath path = OfflineURLPagePath(url); 235 base::FilePath path = OfflineURLPagePath(url);
205 return base::WriteFile(path, html.c_str(), html.length()) < 0; 236 return base::WriteFile(path, html.c_str(), html.length()) < 0;
206 } 237 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698