• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/chromeos/customization_wallpaper_downloader.h"
6 
7 #include <math.h>
8 #include <algorithm>
9 
10 #include "base/files/file_util.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "net/base/load_flags.h"
13 #include "net/http/http_status_code.h"
14 #include "net/url_request/url_fetcher.h"
15 #include "net/url_request/url_request_context_getter.h"
16 #include "url/gurl.h"
17 
18 namespace chromeos {
19 namespace {
20 // This is temporary file suffix (for downloading or resizing).
21 const char kTemporarySuffix[] = ".tmp";
22 
23 // Sleep between wallpaper retries (used multiplied by squared retry number).
24 const unsigned kRetrySleepSeconds = 10;
25 
26 // Retry is infinite with increasing intervals. When calculated delay becomes
27 // longer than maximum (kMaxRetrySleepSeconds) it is set to the maximum.
28 const double kMaxRetrySleepSeconds = 6 * 3600;  // 6 hours
29 
CreateWallpaperDirectory(const base::FilePath & wallpaper_dir,bool * success)30 void CreateWallpaperDirectory(const base::FilePath& wallpaper_dir,
31                               bool* success) {
32   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
33   DCHECK(success);
34 
35   *success = CreateDirectoryAndGetError(wallpaper_dir, NULL);
36   if (!*success) {
37     NOTREACHED() << "Failed to create directory '" << wallpaper_dir.value()
38                  << "'";
39   }
40 }
41 
RenameTemporaryFile(const base::FilePath & from,const base::FilePath & to,bool * success)42 void RenameTemporaryFile(const base::FilePath& from,
43                          const base::FilePath& to,
44                          bool* success) {
45   DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
46   DCHECK(success);
47 
48   base::File::Error error;
49   if (base::ReplaceFile(from, to, &error)) {
50     *success = true;
51   } else {
52     LOG(WARNING)
53         << "Failed to rename temporary file of Customized Wallpaper. error="
54         << error;
55     *success = false;
56   }
57 }
58 
59 }  // namespace
60 
CustomizationWallpaperDownloader(net::URLRequestContextGetter * url_context_getter,const GURL & wallpaper_url,const base::FilePath & wallpaper_dir,const base::FilePath & wallpaper_downloaded_file,base::Callback<void (bool success,const GURL &)> on_wallpaper_fetch_completed)61 CustomizationWallpaperDownloader::CustomizationWallpaperDownloader(
62     net::URLRequestContextGetter* url_context_getter,
63     const GURL& wallpaper_url,
64     const base::FilePath& wallpaper_dir,
65     const base::FilePath& wallpaper_downloaded_file,
66     base::Callback<void(bool success, const GURL&)>
67         on_wallpaper_fetch_completed)
68     : url_context_getter_(url_context_getter),
69       wallpaper_url_(wallpaper_url),
70       wallpaper_dir_(wallpaper_dir),
71       wallpaper_downloaded_file_(wallpaper_downloaded_file),
72       wallpaper_temporary_file_(wallpaper_downloaded_file.value() +
73                                 kTemporarySuffix),
74       retries_(0),
75       retry_delay_(base::TimeDelta::FromSeconds(kRetrySleepSeconds)),
76       on_wallpaper_fetch_completed_(on_wallpaper_fetch_completed),
77       weak_factory_(this) {
78   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
79 }
80 
~CustomizationWallpaperDownloader()81 CustomizationWallpaperDownloader::~CustomizationWallpaperDownloader() {
82   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
83 }
84 
StartRequest()85 void CustomizationWallpaperDownloader::StartRequest() {
86   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
87   DCHECK(wallpaper_url_.is_valid());
88 
89   url_fetcher_.reset(
90       net::URLFetcher::Create(wallpaper_url_, net::URLFetcher::GET, this));
91   url_fetcher_->SetRequestContext(url_context_getter_.get());
92   url_fetcher_->SetLoadFlags(net::LOAD_BYPASS_CACHE |
93                              net::LOAD_DISABLE_CACHE |
94                              net::LOAD_DO_NOT_SAVE_COOKIES |
95                              net::LOAD_DO_NOT_SEND_COOKIES |
96                              net::LOAD_DO_NOT_SEND_AUTH_DATA);
97   base::SequencedWorkerPool* blocking_pool =
98       content::BrowserThread::GetBlockingPool();
99   url_fetcher_->SaveResponseToFileAtPath(
100       wallpaper_temporary_file_,
101       blocking_pool->GetSequencedTaskRunner(blocking_pool->GetSequenceToken()));
102   url_fetcher_->Start();
103 }
104 
Retry()105 void CustomizationWallpaperDownloader::Retry() {
106   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
107   ++retries_;
108 
109   const double delay_seconds = std::min(
110       kMaxRetrySleepSeconds,
111       static_cast<double>(retries_) * retries_ * retry_delay_.InSecondsF());
112   const base::TimeDelta delay = base::TimeDelta::FromSecondsD(delay_seconds);
113 
114   VLOG(1) << "Schedule Customized Wallpaper download in " << delay.InSecondsF()
115           << " seconds (retry = " << retries_ << ").";
116   retry_current_delay_ = delay;
117   request_scheduled_.Start(
118       FROM_HERE, delay, this, &CustomizationWallpaperDownloader::StartRequest);
119 }
120 
Start()121 void CustomizationWallpaperDownloader::Start() {
122   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
123   scoped_ptr<bool> success(new bool(false));
124 
125   base::Closure mkdir_closure = base::Bind(&CreateWallpaperDirectory,
126                                            wallpaper_dir_,
127                                            base::Unretained(success.get()));
128   base::Closure on_created_closure =
129       base::Bind(&CustomizationWallpaperDownloader::OnWallpaperDirectoryCreated,
130                  weak_factory_.GetWeakPtr(),
131                  base::Passed(success.Pass()));
132   if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
133           FROM_HERE, mkdir_closure, on_created_closure)) {
134     LOG(WARNING) << "Failed to start Customized Wallpaper download.";
135   }
136 }
137 
OnWallpaperDirectoryCreated(scoped_ptr<bool> success)138 void CustomizationWallpaperDownloader::OnWallpaperDirectoryCreated(
139     scoped_ptr<bool> success) {
140   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
141   if (*success)
142     StartRequest();
143 }
144 
OnURLFetchComplete(const net::URLFetcher * source)145 void CustomizationWallpaperDownloader::OnURLFetchComplete(
146     const net::URLFetcher* source) {
147   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
148   DCHECK_EQ(url_fetcher_.get(), source);
149 
150   const net::URLRequestStatus status = source->GetStatus();
151   const int response_code = source->GetResponseCode();
152 
153   const bool server_error =
154       !status.is_success() ||
155       (response_code >= net::HTTP_INTERNAL_SERVER_ERROR &&
156        response_code < (net::HTTP_INTERNAL_SERVER_ERROR + 100));
157 
158   VLOG(1) << "CustomizationWallpaperDownloader::OnURLFetchComplete(): status="
159           << status.status();
160 
161   if (server_error) {
162     url_fetcher_.reset();
163     Retry();
164     return;
165   }
166 
167   base::FilePath response_path;
168   url_fetcher_->GetResponseAsFilePath(true, &response_path);
169   url_fetcher_.reset();
170 
171   scoped_ptr<bool> success(new bool(false));
172 
173   base::Closure rename_closure = base::Bind(&RenameTemporaryFile,
174                                             response_path,
175                                             wallpaper_downloaded_file_,
176                                             base::Unretained(success.get()));
177   base::Closure on_rename_closure =
178       base::Bind(&CustomizationWallpaperDownloader::OnTemporaryFileRenamed,
179                  weak_factory_.GetWeakPtr(),
180                  base::Passed(success.Pass()));
181   if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
182           FROM_HERE, rename_closure, on_rename_closure)) {
183     LOG(WARNING)
184         << "Failed to start Customized Wallpaper Rename DownloadedFile.";
185     on_wallpaper_fetch_completed_.Run(false, wallpaper_url_);
186   }
187 }
188 
OnTemporaryFileRenamed(scoped_ptr<bool> success)189 void CustomizationWallpaperDownloader::OnTemporaryFileRenamed(
190     scoped_ptr<bool> success) {
191   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
192   on_wallpaper_fetch_completed_.Run(*success, wallpaper_url_);
193 }
194 
195 }  //   namespace chromeos
196