OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "content/browser/download/download_resource_handler.h" | 5 #include "content/browser/download/download_resource_handler.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 16 matching lines...) Expand all Loading... | |
27 #include "content/public/common/resource_response.h" | 27 #include "content/public/common/resource_response.h" |
28 #include "net/base/io_buffer.h" | 28 #include "net/base/io_buffer.h" |
29 #include "net/base/net_errors.h" | 29 #include "net/base/net_errors.h" |
30 #include "net/http/http_response_headers.h" | 30 #include "net/http/http_response_headers.h" |
31 #include "net/http/http_status_code.h" | 31 #include "net/http/http_status_code.h" |
32 #include "net/url_request/url_request_context.h" | 32 #include "net/url_request/url_request_context.h" |
33 | 33 |
34 namespace content { | 34 namespace content { |
35 namespace { | 35 namespace { |
36 | 36 |
37 void CallStartedCBOnUIThread( | |
38 const DownloadUrlParameters::OnStartedCallback& started_cb, | |
39 DownloadItem* item, | |
40 DownloadInterruptReason interrupt_reason) { | |
41 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
42 | |
43 if (started_cb.is_null()) | |
44 return; | |
45 started_cb.Run(item, interrupt_reason); | |
46 } | |
47 | |
48 // Static function in order to prevent any accidental accesses to | 37 // Static function in order to prevent any accidental accesses to |
49 // DownloadResourceHandler members from the UI thread. | 38 // DownloadResourceHandler members from the UI thread. |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
nit: This comment seems outdated; it implies that
asanka
2014/03/19 20:37:06
Removed comment.
| |
50 static void StartOnUIThread( | 39 void StartOnUIThread( |
51 scoped_ptr<DownloadCreateInfo> info, | 40 scoped_ptr<DownloadCreateInfo> info, |
52 scoped_ptr<ByteStreamReader> stream, | 41 scoped_ptr<ByteStreamReader> stream, |
53 const DownloadUrlParameters::OnStartedCallback& started_cb) { | 42 const DownloadUrlParameters::OnStartedCallback& started_cb) { |
54 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
55 | 44 |
56 DownloadManager* download_manager = info->request_handle.GetDownloadManager(); | 45 DownloadManager* download_manager = info->request_handle.GetDownloadManager(); |
57 if (!download_manager) { | 46 if (!download_manager) { |
58 // NULL in unittests or if the page closed right after starting the | 47 // NULL in unittests or if the page closed right after starting the |
59 // download. | 48 // download. |
60 if (!started_cb.is_null()) | 49 if (!started_cb.is_null()) |
61 started_cb.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); | 50 started_cb.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); |
62 | 51 |
63 // |stream| gets deleted on non-FILE thread, but it's ok since | 52 // |stream| gets deleted on non-FILE thread, but it's ok since |
64 // we're not using stream_writer_ yet. | 53 // we're not using stream_writer_ yet. |
65 | 54 |
66 return; | 55 return; |
67 } | 56 } |
68 | 57 |
69 download_manager->StartDownload(info.Pass(), stream.Pass(), started_cb); | 58 download_manager->StartDownload(info.Pass(), stream.Pass(), started_cb); |
70 } | 59 } |
71 | 60 |
61 DownloadInterruptReason HTTPResponseCodeToInterruptReason(int response_code) { | |
62 switch (response_code) { | |
63 case -1: // Non-HTTP request. | |
64 case net::HTTP_OK: | |
65 case net::HTTP_CREATED: | |
66 case net::HTTP_ACCEPTED: | |
67 case net::HTTP_NON_AUTHORITATIVE_INFORMATION: | |
68 case net::HTTP_RESET_CONTENT: | |
69 case net::HTTP_PARTIAL_CONTENT: | |
70 return DOWNLOAD_INTERRUPT_REASON_NONE; | |
71 case net::HTTP_NO_CONTENT: | |
72 case net::HTTP_NOT_FOUND: | |
73 return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT; | |
74 case net::HTTP_PRECONDITION_FAILED: | |
75 // Failed our 'If-Unmodified-Since' or 'If-Match'; see | |
76 // download_manager_impl.cc BeginDownload() | |
77 return DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION; | |
78 case net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: | |
79 // Retry by downloading from the start automatically: | |
80 // If we haven't received data when we get this error, we won't. | |
81 return DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE; | |
82 // TODO(asanka): Add handling for 5xx errors with backoff semantics. | |
83 default: // All other errors. | |
84 // Redirection and informational codes should have been handled earlier | |
85 // in the stack. | |
86 DCHECK_NE(3, response_code / 100); | |
87 DCHECK_NE(1, response_code / 100); | |
88 return DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED; | |
89 } | |
90 } | |
91 | |
72 } // namespace | 92 } // namespace |
73 | 93 |
74 const int DownloadResourceHandler::kDownloadByteStreamSize = 100 * 1024; | 94 const int DownloadResourceHandler::kDownloadByteStreamSize = 100 * 1024; |
75 | 95 |
76 DownloadResourceHandler::DownloadResourceHandler( | 96 DownloadResourceHandler::DownloadResourceHandler( |
77 uint32 id, | 97 uint32 id, |
78 net::URLRequest* request, | 98 net::URLRequest* request, |
79 const DownloadUrlParameters::OnStartedCallback& started_cb, | 99 const DownloadUrlParameters::OnStartedCallback& started_cb, |
80 scoped_ptr<DownloadSaveInfo> save_info) | 100 scoped_ptr<DownloadSaveInfo> save_info) |
81 : ResourceHandler(request), | 101 : ResourceHandler(request), |
82 download_id_(id), | 102 download_id_(id), |
83 started_cb_(started_cb), | 103 started_cb_(started_cb), |
84 save_info_(save_info.Pass()), | 104 save_info_(save_info.Pass()), |
85 last_buffer_size_(0), | 105 last_buffer_size_(0), |
86 bytes_read_(0), | 106 bytes_read_(0), |
87 pause_count_(0), | 107 pause_count_(0), |
88 was_deferred_(false), | 108 was_deferred_(false), |
89 on_response_started_called_(false) { | 109 download_manager_notified_(false) { |
90 RecordDownloadCount(UNTHROTTLED_COUNT); | 110 RecordDownloadCount(UNTHROTTLED_COUNT); |
91 } | 111 } |
92 | 112 |
93 bool DownloadResourceHandler::OnUploadProgress(int request_id, | 113 bool DownloadResourceHandler::OnUploadProgress(int request_id, |
94 uint64 position, | 114 uint64 position, |
95 uint64 size) { | 115 uint64 size) { |
96 return true; | 116 return true; |
97 } | 117 } |
98 | 118 |
99 bool DownloadResourceHandler::OnRequestRedirected( | 119 bool DownloadResourceHandler::OnRequestRedirected( |
100 int request_id, | 120 int request_id, |
101 const GURL& url, | 121 const GURL& url, |
102 ResourceResponse* response, | 122 ResourceResponse* response, |
103 bool* defer) { | 123 bool* defer) { |
104 // We treat a download as a main frame load, and thus update the policy URL | 124 // We treat a download as a main frame load, and thus update the policy URL |
105 // on redirects. | 125 // on redirects. |
106 request()->set_first_party_for_cookies(url); | 126 request()->set_first_party_for_cookies(url); |
107 return true; | 127 return true; |
108 } | 128 } |
109 | 129 |
110 // Send the download creation information to the download thread. | 130 // Send the download creation information to the download thread. |
111 bool DownloadResourceHandler::OnResponseStarted( | 131 bool DownloadResourceHandler::OnResponseStarted( |
112 int request_id, | 132 int request_id, |
113 ResourceResponse* response, | 133 ResourceResponse* response, |
114 bool* defer) { | 134 bool* defer) { |
115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
116 // There can be only one (call) | |
117 DCHECK(!on_response_started_called_); | |
118 on_response_started_called_ = true; | |
119 | |
120 VLOG(20) << __FUNCTION__ << "()" << DebugString() | 136 VLOG(20) << __FUNCTION__ << "()" << DebugString() |
121 << " request_id = " << request_id; | 137 << " request_id = " << request_id; |
122 download_start_time_ = base::TimeTicks::Now(); | 138 download_start_time_ = base::TimeTicks::Now(); |
123 | 139 |
124 // If it's a download, we don't want to poison the cache with it. | 140 // If it's a download, we don't want to poison the cache with it. |
125 request()->StopCaching(); | 141 request()->StopCaching(); |
126 | 142 |
127 // Lower priority as well, so downloads don't contend for resources | 143 // Lower priority as well, so downloads don't contend for resources |
128 // with main frames. | 144 // with main frames. |
129 request()->SetPriority(net::IDLE); | 145 request()->SetPriority(net::IDLE); |
130 | 146 |
147 const net::HttpResponseHeaders* headers = request()->response_headers(); | |
148 DownloadInterruptReason interrupt_reason = | |
149 (headers ? HTTPResponseCodeToInterruptReason(headers->response_code()) | |
150 : DOWNLOAD_INTERRUPT_REASON_NONE); | |
151 | |
152 if (interrupt_reason != DOWNLOAD_INTERRUPT_REASON_NONE) | |
153 NotifyDownloadManagerOfFailedRequest(interrupt_reason); | |
154 else | |
155 NotifyDownloadManagerOfSuccessfulResponseStart(response); | |
156 | |
157 return true; | |
158 } | |
159 | |
160 void DownloadResourceHandler::NotifyDownloadManagerOfSuccessfulResponseStart( | |
161 ResourceResponse* response) { | |
162 // NotifyDownloadManagerOfFailedRequest or | |
163 // NotifyDownloadManagerOfSuccessfulResponseStart can only be called once. | |
164 DCHECK(!download_manager_notified_); | |
165 download_manager_notified_ = true; | |
166 | |
167 const ResourceRequestInfoImpl* request_info = GetRequestInfo(); | |
168 const net::HttpResponseHeaders* headers = request()->response_headers(); | |
169 | |
131 // If the content-length header is not present (or contains something other | 170 // If the content-length header is not present (or contains something other |
132 // than numbers), the incoming content_length is -1 (unknown size). | 171 // than numbers), the incoming content_length is -1 (unknown size). |
133 // Set the content length to 0 to indicate unknown size to DownloadManager. | 172 // Set the content length to 0 to indicate unknown size to DownloadManager. |
134 int64 content_length = | 173 int64 content_length = |
135 response->head.content_length > 0 ? response->head.content_length : 0; | 174 response->head.content_length > 0 ? response->head.content_length : 0; |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
nit, question: It feels a little funny to be both
asanka
2014/03/19 20:37:06
The URLRequestJob provides the expected content le
| |
136 | 175 |
137 const ResourceRequestInfoImpl* request_info = GetRequestInfo(); | |
138 | |
139 // Deleted in DownloadManager. | |
140 scoped_ptr<DownloadCreateInfo> info( | 176 scoped_ptr<DownloadCreateInfo> info( |
141 new DownloadCreateInfo(base::Time::Now(), | 177 new DownloadCreateInfo(base::Time::Now(), |
142 content_length, | 178 content_length, |
143 request()->net_log(), | 179 request()->net_log(), |
144 request_info->HasUserGesture(), | 180 request_info->HasUserGesture(), |
145 request_info->GetPageTransition(), | 181 request_info->GetPageTransition(), |
146 save_info_.Pass())); | 182 save_info_.Pass())); |
147 | 183 |
148 // Create the ByteStream for sending data to the download sink. | |
149 scoped_ptr<ByteStreamReader> stream_reader; | |
150 CreateByteStream( | |
151 base::MessageLoopProxy::current(), | |
152 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), | |
153 kDownloadByteStreamSize, &stream_writer_, &stream_reader); | |
154 stream_writer_->RegisterCallback( | |
155 base::Bind(&DownloadResourceHandler::ResumeRequest, AsWeakPtr())); | |
156 | |
157 info->download_id = download_id_; | |
158 info->url_chain = request()->url_chain(); | |
159 info->referrer_url = GURL(request()->referrer()); | |
160 info->mime_type = response->head.mime_type; | |
161 info->remote_address = request()->GetSocketAddress().host(); | |
162 request()->GetResponseHeaderByName("content-disposition", | |
163 &info->content_disposition); | |
164 RecordDownloadMimeType(info->mime_type); | |
165 RecordDownloadContentDisposition(info->content_disposition); | |
166 | |
167 info->request_handle = | |
168 DownloadRequestHandle(AsWeakPtr(), request_info->GetChildID(), | |
169 request_info->GetRouteID(), | |
170 request_info->GetRequestID()); | |
171 | |
172 // Get the last modified time and etag. | |
173 const net::HttpResponseHeaders* headers = request()->response_headers(); | |
174 if (headers) { | 184 if (headers) { |
175 if (headers->HasStrongValidators()) { | 185 if (headers->HasStrongValidators()) { |
176 // If we don't have strong validators as per RFC 2616 section 13.3.3, then | 186 // If we don't have strong validators as per RFC 2616 section 13.3.3, then |
177 // we neither store nor use them for range requests. | 187 // we neither store nor use them for range requests. |
178 if (!headers->EnumerateHeader(NULL, "Last-Modified", | 188 if (!headers->EnumerateHeader(NULL, "Last-Modified", |
179 &info->last_modified)) | 189 &info->last_modified)) |
180 info->last_modified.clear(); | 190 info->last_modified.clear(); |
181 if (!headers->EnumerateHeader(NULL, "ETag", &info->etag)) | 191 if (!headers->EnumerateHeader(NULL, "ETag", &info->etag)) |
182 info->etag.clear(); | 192 info->etag.clear(); |
183 } | 193 } |
184 | 194 |
185 int status = headers->response_code(); | 195 int status = headers->response_code(); |
186 if (2 == status / 100 && status != net::HTTP_PARTIAL_CONTENT) { | 196 if (2 == status / 100 && status != net::HTTP_PARTIAL_CONTENT) { |
187 // Success & not range response; if we asked for a range, we didn't | 197 // Success & not range response; if we asked for a range, we didn't |
188 // get it--reset the file pointers to reflect that. | 198 // get it--reset the file pointers to reflect that. |
189 info->save_info->offset = 0; | 199 info->save_info->offset = 0; |
190 info->save_info->hash_state = ""; | 200 info->save_info->hash_state = ""; |
191 } | 201 } |
192 | 202 |
193 if (!headers->GetMimeType(&info->original_mime_type)) | 203 if (!headers->GetMimeType(&info->original_mime_type)) |
194 info->original_mime_type.clear(); | 204 info->original_mime_type.clear(); |
195 } | 205 } |
196 | 206 |
207 info->download_id = download_id_; | |
208 info->url_chain = request()->url_chain(); | |
209 info->referrer_url = GURL(request()->referrer()); | |
210 | |
211 scoped_ptr<ByteStreamReader> stream_reader; | |
212 // Create the ByteStream for sending data to the download sink. | |
213 CreateByteStream( | |
214 base::MessageLoopProxy::current(), | |
215 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), | |
216 kDownloadByteStreamSize, | |
217 &stream_writer_, | |
218 &stream_reader); | |
219 stream_writer_->RegisterCallback( | |
220 base::Bind(&DownloadResourceHandler::ResumeRequest, AsWeakPtr())); | |
221 | |
222 info->mime_type = response->head.mime_type; | |
223 info->remote_address = request()->GetSocketAddress().host(); | |
224 request()->GetResponseHeaderByName("content-disposition", | |
225 &info->content_disposition); | |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
nit, suggestion: It makes some sense to me to swit
asanka
2014/03/19 20:37:06
Done.
| |
226 RecordDownloadMimeType(info->mime_type); | |
227 RecordDownloadContentDisposition(info->content_disposition); | |
228 | |
229 info->request_handle = DownloadRequestHandle(AsWeakPtr(), | |
230 request_info->GetChildID(), | |
231 request_info->GetRouteID(), | |
232 request_info->GetRequestID()); | |
233 | |
197 BrowserThread::PostTask( | 234 BrowserThread::PostTask( |
198 BrowserThread::UI, FROM_HERE, | 235 BrowserThread::UI, FROM_HERE, |
199 base::Bind(&StartOnUIThread, | 236 base::Bind(&StartOnUIThread, |
200 base::Passed(&info), | 237 base::Passed(&info), |
201 base::Passed(&stream_reader), | 238 base::Passed(&stream_reader), |
202 // Pass to StartOnUIThread so that variable | 239 // Pass to StartOnUIThread so that variable |
203 // access is always on IO thread but function | 240 // access is always on IO thread but function |
204 // is called on UI thread. | 241 // is called on UI thread. |
205 started_cb_)); | 242 started_cb_)); |
206 // Guaranteed to be called in StartOnUIThread | 243 // Guaranteed to be called in StartOnUIThread |
207 started_cb_.Reset(); | 244 started_cb_.Reset(); |
208 | |
209 return true; | |
210 } | 245 } |
211 | 246 |
212 void DownloadResourceHandler::CallStartedCB( | 247 void DownloadResourceHandler::NotifyDownloadManagerOfFailedRequest( |
213 DownloadItem* item, | |
214 DownloadInterruptReason interrupt_reason) { | 248 DownloadInterruptReason interrupt_reason) { |
215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 249 // NotifyDownloadManagerOfFailedRequest or |
216 if (started_cb_.is_null()) | 250 // NotifyDownloadManagerOfSuccessfulResponseStart can only be called once. |
217 return; | 251 DCHECK(!download_manager_notified_); |
218 BrowserThread::PostTask( | 252 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason); |
219 BrowserThread::UI, | 253 download_manager_notified_ = true; |
220 FROM_HERE, | 254 |
221 base::Bind( | 255 const ResourceRequestInfoImpl* request_info = GetRequestInfo(); |
222 &CallStartedCBOnUIThread, started_cb_, item, interrupt_reason)); | 256 |
257 scoped_ptr<DownloadCreateInfo> info( | |
258 new DownloadCreateInfo(base::Time::Now(), | |
259 -1, | |
260 request()->net_log(), | |
261 false, | |
262 request_info->GetPageTransition(), | |
263 save_info_.Pass())); | |
264 info->download_id = download_id_; | |
265 info->url_chain = request()->url_chain(); | |
266 info->referrer_url = GURL(request()->referrer()); | |
267 info->interrupt_reason = interrupt_reason; | |
268 info->remote_address = request()->GetSocketAddress().host(); | |
269 info->request_handle = DownloadRequestHandle(AsWeakPtr(), | |
270 request_info->GetChildID(), | |
271 request_info->GetRouteID(), | |
272 request_info->GetRequestID()); | |
273 | |
274 scoped_ptr<ByteStreamReader> stream_reader; | |
275 BrowserThread::PostTask(BrowserThread::UI, | |
276 FROM_HERE, | |
277 base::Bind(&StartOnUIThread, | |
278 base::Passed(&info), | |
279 base::Passed(&stream_reader), | |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
nit: I think it'd be clearer to cons up a null one
asanka
2014/03/19 20:37:06
Done.
| |
280 started_cb_)); | |
223 started_cb_.Reset(); | 281 started_cb_.Reset(); |
224 } | 282 } |
225 | 283 |
226 bool DownloadResourceHandler::OnWillStart(int request_id, | 284 bool DownloadResourceHandler::OnWillStart(int request_id, |
227 const GURL& url, | 285 const GURL& url, |
228 bool* defer) { | 286 bool* defer) { |
229 return true; | 287 return true; |
230 } | 288 } |
231 | 289 |
232 bool DownloadResourceHandler::OnBeforeNetworkStart(int request_id, | 290 bool DownloadResourceHandler::OnBeforeNetworkStart(int request_id, |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
270 double potential_bandwidth = last_buffer_size_/seconds_since_last_read; | 328 double potential_bandwidth = last_buffer_size_/seconds_since_last_read; |
271 RecordBandwidth(actual_bandwidth, potential_bandwidth); | 329 RecordBandwidth(actual_bandwidth, potential_bandwidth); |
272 } | 330 } |
273 last_read_time_ = now; | 331 last_read_time_ = now; |
274 | 332 |
275 if (!bytes_read) | 333 if (!bytes_read) |
276 return true; | 334 return true; |
277 bytes_read_ += bytes_read; | 335 bytes_read_ += bytes_read; |
278 DCHECK(read_buffer_.get()); | 336 DCHECK(read_buffer_.get()); |
279 | 337 |
338 // If this was an error response, then stream_writer_ would be NULL. | |
339 if (!stream_writer_) { | |
340 read_buffer_ = NULL; | |
341 return true; | |
342 } | |
343 | |
280 // Take the data ship it down the stream. If the stream is full, pause the | 344 // Take the data ship it down the stream. If the stream is full, pause the |
281 // request; the stream callback will resume it. | 345 // request; the stream callback will resume it. |
282 if (!stream_writer_->Write(read_buffer_, bytes_read)) { | 346 if (!stream_writer_->Write(read_buffer_, bytes_read)) { |
283 PauseRequest(); | 347 PauseRequest(); |
284 *defer = was_deferred_ = true; | 348 *defer = was_deferred_ = true; |
285 last_stream_pause_time_ = now; | 349 last_stream_pause_time_ = now; |
286 } | 350 } |
287 | 351 |
288 read_buffer_ = NULL; // Drop our reference. | 352 read_buffer_ = NULL; // Drop our reference. |
289 | 353 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
334 // stack cancelled the request. There aren't that many things that | 398 // stack cancelled the request. There aren't that many things that |
335 // could do this to a download request (whose lifetime is separated from | 399 // could do this to a download request (whose lifetime is separated from |
336 // the tab from which it came). We map this to USER_CANCELLED as the | 400 // the tab from which it came). We map this to USER_CANCELLED as the |
337 // case we know about (system suspend because of laptop close) corresponds | 401 // case we know about (system suspend because of laptop close) corresponds |
338 // to a user action. | 402 // to a user action. |
339 // TODO(ahendrickson) -- Find a better set of codes to use here, as | 403 // TODO(ahendrickson) -- Find a better set of codes to use here, as |
340 // CANCELED/ERR_ABORTED can occur for reasons other than user cancel. | 404 // CANCELED/ERR_ABORTED can occur for reasons other than user cancel. |
341 reason = DOWNLOAD_INTERRUPT_REASON_USER_CANCELED; | 405 reason = DOWNLOAD_INTERRUPT_REASON_USER_CANCELED; |
342 } | 406 } |
343 | 407 |
344 if (status.is_success() && | |
345 reason == DOWNLOAD_INTERRUPT_REASON_NONE && | |
346 request()->response_headers()) { | |
347 // Handle server's response codes. | |
348 switch(response_code) { | |
349 case -1: // Non-HTTP request. | |
350 case net::HTTP_OK: | |
351 case net::HTTP_CREATED: | |
352 case net::HTTP_ACCEPTED: | |
353 case net::HTTP_NON_AUTHORITATIVE_INFORMATION: | |
354 case net::HTTP_RESET_CONTENT: | |
355 case net::HTTP_PARTIAL_CONTENT: | |
356 // Expected successful codes. | |
357 break; | |
358 case net::HTTP_NO_CONTENT: | |
359 case net::HTTP_NOT_FOUND: | |
360 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT; | |
361 break; | |
362 case net::HTTP_PRECONDITION_FAILED: | |
363 // Failed our 'If-Unmodified-Since' or 'If-Match'; see | |
364 // download_manager_impl.cc BeginDownload() | |
365 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION; | |
366 break; | |
367 case net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: | |
368 // Retry by downloading from the start automatically: | |
369 // If we haven't received data when we get this error, we won't. | |
370 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE; | |
371 break; | |
372 default: // All other errors. | |
373 // Redirection and informational codes should have been handled earlier | |
374 // in the stack. | |
375 DCHECK_NE(3, response_code / 100); | |
376 DCHECK_NE(1, response_code / 100); | |
377 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED; | |
378 break; | |
379 } | |
380 } | |
381 | |
382 std::string accept_ranges; | 408 std::string accept_ranges; |
383 bool has_strong_validators = false; | 409 bool has_strong_validators = false; |
384 if (request()->response_headers()) { | 410 if (request()->response_headers()) { |
385 request()->response_headers()->EnumerateHeader( | 411 request()->response_headers()->EnumerateHeader( |
386 NULL, "Accept-Ranges", &accept_ranges); | 412 NULL, "Accept-Ranges", &accept_ranges); |
387 has_strong_validators = | 413 has_strong_validators = |
388 request()->response_headers()->HasStrongValidators(); | 414 request()->response_headers()->HasStrongValidators(); |
389 } | 415 } |
390 RecordAcceptsRanges(accept_ranges, bytes_read_, has_strong_validators); | 416 RecordAcceptsRanges(accept_ranges, bytes_read_, has_strong_validators); |
391 RecordNetworkBlockage(base::TimeTicks::Now() - download_start_time_, | 417 RecordNetworkBlockage(base::TimeTicks::Now() - download_start_time_, |
392 total_pause_time_); | 418 total_pause_time_); |
393 | 419 |
394 CallStartedCB(NULL, reason); | 420 // If OnResponseCompleted() is called without a corresponding |
395 | 421 // OnResponseStarted() call, then the DownloadManager wouldn't have been |
396 // Send the info down the stream. Conditional is in case we get | 422 // notified. |
397 // OnResponseCompleted without OnResponseStarted. | 423 if (!download_manager_notified_ && |
398 if (stream_writer_) | 424 status.status() != net::URLRequestStatus::CANCELED) { |
425 DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, reason); | |
426 NotifyDownloadManagerOfFailedRequest(reason); | |
427 } else if (stream_writer_) { | |
428 // Send the info down the stream. Conditional is in case we get | |
429 // OnResponseCompleted without OnResponseStarted. | |
399 stream_writer_->Close(reason); | 430 stream_writer_->Close(reason); |
431 stream_writer_.reset(); // We no longer need the stream. | |
432 } | |
400 | 433 |
401 // If the error mapped to something unknown, record it so that | 434 // If the error mapped to something unknown, record it so that |
402 // we can drill down. | 435 // we can drill down. |
403 if (reason == DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED) { | 436 if (reason == DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED) { |
404 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Download.MapErrorNetworkFailed", | 437 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Download.MapErrorNetworkFailed", |
405 std::abs(status.error()), | 438 std::abs(status.error()), |
406 net::GetAllErrorCodesForUma()); | 439 net::GetAllErrorCodesForUma()); |
407 } | 440 } |
408 | 441 |
409 stream_writer_.reset(); // We no longer need the stream. | |
410 read_buffer_ = NULL; | 442 read_buffer_ = NULL; |
411 } | 443 } |
412 | 444 |
413 void DownloadResourceHandler::OnDataDownloaded( | 445 void DownloadResourceHandler::OnDataDownloaded( |
414 int request_id, | 446 int request_id, |
415 int bytes_downloaded) { | 447 int bytes_downloaded) { |
416 NOTREACHED(); | 448 NOTREACHED(); |
417 } | 449 } |
418 | 450 |
419 void DownloadResourceHandler::PauseRequest() { | 451 void DownloadResourceHandler::PauseRequest() { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
466 request()->url().spec().c_str() : | 498 request()->url().spec().c_str() : |
467 "<NULL request>", | 499 "<NULL request>", |
468 info->GetChildID(), | 500 info->GetChildID(), |
469 info->GetRequestID(), | 501 info->GetRequestID(), |
470 info->GetRouteID()); | 502 info->GetRouteID()); |
471 } | 503 } |
472 | 504 |
473 DownloadResourceHandler::~DownloadResourceHandler() { | 505 DownloadResourceHandler::~DownloadResourceHandler() { |
474 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 506 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
475 | 507 |
476 // This won't do anything if the callback was called before. | 508 // DownloadManager would not be notified if: |
477 // If it goes through, it will likely be because OnWillStart() returned | 509 // |
478 // false somewhere in the chain of resource handlers. | 510 // - The Content-Type or Content-Disposition indicated that the entity should |
479 CallStartedCB(NULL, DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED); | 511 // be downloaded, but the response code was not 2xx. BufferedResourceHandler |
512 // will create a DownloadResourceHandler, but won't invoke it. | |
513 // TODO(asanka): Fix this so that ResourceHandlers are only created if they | |
514 // are going to be used. | |
515 // | |
516 // - OnWillStart() returned false somewhere in the chain of resource handlers. | |
517 if (!download_manager_notified_ && !started_cb_.is_null()) | |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
DCHECK opportunity? Shouldn't these two condition
asanka
2014/03/19 20:37:06
After verifying the OnWillStart() pathway, I decid
| |
518 BrowserThread::PostTask( | |
519 BrowserThread::UI, | |
520 FROM_HERE, | |
521 base::Bind(started_cb_, | |
Randy Smith (Not in Mondays)
2014/03/18 21:07:28
Is the eventual intent to get rid of started_cb?
asanka
2014/03/19 20:37:06
Yeah. I'd like to get rid of started_cb_. I added
| |
522 static_cast<DownloadItem*>(NULL), | |
523 DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED)); | |
480 | 524 |
481 // Remove output stream callback if a stream exists. | 525 // Remove output stream callback if a stream exists. |
482 if (stream_writer_) | 526 if (stream_writer_) |
483 stream_writer_->RegisterCallback(base::Closure()); | 527 stream_writer_->RegisterCallback(base::Closure()); |
484 | 528 |
485 UMA_HISTOGRAM_TIMES("SB2.DownloadDuration", | 529 UMA_HISTOGRAM_TIMES("SB2.DownloadDuration", |
486 base::TimeTicks::Now() - download_start_time_); | 530 base::TimeTicks::Now() - download_start_time_); |
487 } | 531 } |
488 | 532 |
489 } // namespace content | 533 } // namespace content |
OLD | NEW |