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

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

Issue 23496076: WIP - Refactor programmatic downloads Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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 "content/browser/download/url_downloader.h"
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "content/browser/download/download_create_info.h"
10 #include "content/browser/download/download_interrupt_reasons_impl.h"
11 #include "content/browser/download/download_request_handle.h"
12 #include "content/browser/download/download_request_model.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/download_url_parameters.h"
15 #include "net/url_request/url_request.h"
16
17 namespace content {
18
19 class UrlDownloader::RequestHandle : public DownloadRequestHandle {
20 public:
21 RequestHandle(scoped_ptr<UrlDownloader> downloader);
22 virtual ~RequestHandle();
23
24 private:
25 // DownloadRequestHandle.
26 virtual void Start(const RequestStartedCallback& callback) OVERRIDE;
27 virtual void PauseRequest() const OVERRIDE;
28 virtual void ResumeRequest() const OVERRIDE;
29 virtual void CancelRequest() const OVERRIDE;
30 virtual std::string DebugString() const OVERRIDE;
31
32 scoped_ptr<UrlDownloader> downloader_;
33
34 DISALLOW_COPY_AND_ASSIGN(RequestHandle);
35 };
36
37 UrlDownloader::RequestHandle::RequestHandle(
38 scoped_ptr<UrlDownloader> downloader)
39 : downloader_(downloader.Pass()) {}
40
41 UrlDownloader::RequestHandle::~RequestHandle() {
42 BrowserThread::DeleteSoon(
43 BrowserThread::IO, FROM_HERE, downloader_.release());
44 }
45
46 void UrlDownloader::RequestHandle::Start(
47 const RequestStartedCallback& callback) {
48 BrowserThread::PostTask(BrowserThread::IO,
49 FROM_HERE,
50 base::Bind(&UrlDownloader::Start,
51 base::Unretained(downloader_.get()),
52 callback));
53 }
54
55 void UrlDownloader::RequestHandle::PauseRequest() const {
56 BrowserThread::PostTask(BrowserThread::IO,
57 FROM_HERE,
58 base::Bind(&UrlDownloader::PauseRequest,
59 base::Unretained(downloader_.get())));
60 }
61
62 void UrlDownloader::RequestHandle::ResumeRequest() const {
63 BrowserThread::PostTask(BrowserThread::IO,
64 FROM_HERE,
65 base::Bind(&UrlDownloader::ResumeRequest,
66 base::Unretained(downloader_.get())));
67 }
68
69 void UrlDownloader::RequestHandle::CancelRequest() const {
70 BrowserThread::PostTask(BrowserThread::IO,
71 FROM_HERE,
72 base::Bind(&UrlDownloader::CancelRequest,
73 base::Unretained(downloader_.get())));
74 }
75
76 std::string UrlDownloader::RequestHandle::DebugString() const {
77 return std::string();
78 }
79
80 // static
81 scoped_ptr<DownloadRequestHandle> UrlDownloader::CreateDownloadRequest(
82 scoped_ptr<DownloadUrlParameters> params) {
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84 scoped_ptr<UrlDownloader> downloader(new UrlDownloader(params.Pass()));
85 scoped_ptr<DownloadRequestHandle> request_handle(
86 new RequestHandle(downloader.Pass()));
87 return request_handle.Pass();
88 }
89
90 UrlDownloader::UrlDownloader(scoped_ptr<DownloadUrlParameters> params)
91 : params_(params.Pass()),
92 child_process_id_(params_->render_process_host_id()),
93 is_request_active_(true) {
94 // Can be created on the UI thread.
95 }
96
97 UrlDownloader::~UrlDownloader() {}
98
99 void UrlDownloader::Start(const RequestStartedCallback& callback) {
100 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
101 started_callback_ = callback;
102 request_ = DownloadRequestModel::CreateRequest(*params_, this).Pass();
103 if (!request_) {
104 scoped_ptr<DownloadCreateInfo> empty_create_info;
105 BrowserThread::PostTask(
106 BrowserThread::UI,
107 FROM_HERE,
108 base::Bind(callback,
109 DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST,
110 base::Passed(&empty_create_info)));
111 return;
112 }
113
114 scoped_ptr<DownloadSaveInfo> save_info(new DownloadSaveInfo());
115 save_info->file_path = params_->file_path();
116 save_info->suggested_name = params_->suggested_name();
117 save_info->offset = params_->offset();
118 save_info->hash_state = params_->hash_state();
119 save_info->prompt_for_save_location = params_->prompt();
120 save_info->file_stream = params_->GetFileStream();
121
122 // TODO(asanka): This request will not have the LOAD_MAYBE_USER_GESTURE flag
123 // set. This is correct since this is a programmatic download. Make sure that
124 // this doesn't affect resumption since a download that was considered safe
125 // before may be considered dangerous on resumption.
126
127 request_model_.reset(
128 new DownloadRequestModel(request_.get(), save_info.Pass()));
129 request_->Start();
130 }
131
132 void UrlDownloader::OnReceivedRedirect(net::URLRequest* request,
133 const GURL& new_url,
134 bool* defer_redirect) {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
136 if (!DownloadRequestModel::IsRequestAllowed(new_url, child_process_id_)) {
137 request_model_->OnDownloadInterrupted(
138 DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST);
139 request_->Cancel();
140 return;
141 }
142 request_model_->OnRequestRedirected(new_url);
143 }
144
145 void UrlDownloader::OnResponseStarted(net::URLRequest* request) {
146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
147 if (!request_->status().is_success()) {
148 DownloadInterruptReason reason = ConvertNetErrorToInterruptReason(
149 static_cast<net::Error>(request_->status().error()),
150 DOWNLOAD_INTERRUPT_FROM_NETWORK);
151 scoped_ptr<DownloadCreateInfo> empty_create_info;
152 BrowserThread::PostTask(
153 BrowserThread::UI,
154 FROM_HERE,
155 base::Bind(
156 started_callback_, reason, base::Passed(&empty_create_info)));
157 request_->Cancel();
158 return;
159 }
160
161 scoped_ptr<DownloadCreateInfo> create_info =
162 request_model_->OnResponseStarted(
163 std::string(),
164 false,
165 PAGE_TRANSITION_LINK,
166 base::Bind(&UrlDownloader::ResumeRequest, base::Unretained(this)));
167 BrowserThread::PostTask(BrowserThread::UI,
168 FROM_HERE,
169 base::Bind(started_callback_,
170 DOWNLOAD_INTERRUPT_REASON_NONE,
171 base::Passed(&create_info)));
172 ReadNextChunk();
173 }
174
175 void UrlDownloader::OnReadCompleted(net::URLRequest* request, int bytes_read) {
176 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
177 HandleCompletedRead(bytes_read);
178 ReadNextChunk();
179 }
180
181 void UrlDownloader::PauseRequest() {
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
183 request_model_->OnPauseRequest();
184 }
185
186 void UrlDownloader::ResumeRequest() {
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
188 if (request_model_->OnResumeRequest() ==
189 DownloadRequestModel::READY_TO_READ &&
190 !is_request_active_ &&
191 request_->status().is_success())
192 ReadNextChunk();
193 }
194
195 void UrlDownloader::CancelRequest() {
196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
197 request_->Cancel();
198 }
199
200 void UrlDownloader::ReadNextChunk() {
201 net::IOBuffer* buffer = NULL;
202 int buf_size = 0;
203 int bytes_read = 0;
204 bool read_succeeded = false;
205
206 if (!is_request_active_)
207 return;
208
209 do {
210 request_model_->OnWillRead(&buffer, &buf_size, -1);
211 DCHECK_LT(0, buf_size);
212
213 // TODO(asanka): Check for re-entrancy issues. Can Read() result in a call
214 // into OnReadCompleted()?
215 read_succeeded = request_->Read(buffer, buf_size, &bytes_read);
216
217 // Read returns false if IO is pending or if the read failed.
218 if (read_succeeded || !request_->status().is_success())
219 HandleCompletedRead(bytes_read);
220 } while(read_succeeded && is_request_active_);
221 }
222
223 void UrlDownloader::HandleCompletedRead(int bytes_read) {
224 DownloadRequestModel::ReadState read_state =
225 request_model_->OnReadCompleted(bytes_read);
226 is_request_active_ = (read_state == DownloadRequestModel::READY_TO_READ);
227 if (bytes_read == 0 || !request_->status().is_success()) {
228 request_model_->OnResponseCompleted();
229 is_request_active_ = false;
230 }
231 }
232
233 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/download/url_downloader.h ('k') | content/browser/download/url_downloader_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698