| 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 10 matching lines...) Expand all Loading... |
| 21 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 21 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| 22 #include "content/browser/loader/resource_request_info_impl.h" | 22 #include "content/browser/loader/resource_request_info_impl.h" |
| 23 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
| 24 #include "content/public/browser/download_interrupt_reasons.h" | 24 #include "content/public/browser/download_interrupt_reasons.h" |
| 25 #include "content/public/browser/download_item.h" | 25 #include "content/public/browser/download_item.h" |
| 26 #include "content/public/browser/download_manager_delegate.h" | 26 #include "content/public/browser/download_manager_delegate.h" |
| 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/url_request/url_request_context.h" | 32 #include "net/url_request/url_request_context.h" |
| 32 | 33 |
| 33 namespace content { | 34 namespace content { |
| 34 namespace { | 35 namespace { |
| 35 | 36 |
| 36 static const int kDownloadByteStreamSize = 100 * 1024; | 37 static const int kDownloadByteStreamSize = 100 * 1024; |
| 37 | 38 |
| 38 void CallStartedCBOnUIThread( | 39 void CallStartedCBOnUIThread( |
| 39 const DownloadResourceHandler::OnStartedCallback& started_cb, | 40 const DownloadResourceHandler::OnStartedCallback& started_cb, |
| 40 DownloadItem* item, | 41 DownloadItem* item, |
| (...skipping 25 matching lines...) Expand all Loading... |
| 66 DownloadItem* item = download_manager->StartDownload( | 67 DownloadItem* item = download_manager->StartDownload( |
| 67 info.Pass(), stream.Pass()); | 68 info.Pass(), stream.Pass()); |
| 68 | 69 |
| 69 if (!started_cb.is_null()) | 70 if (!started_cb.is_null()) |
| 70 started_cb.Run(item, net::OK); | 71 started_cb.Run(item, net::OK); |
| 71 } | 72 } |
| 72 | 73 |
| 73 } // namespace | 74 } // namespace |
| 74 | 75 |
| 75 DownloadResourceHandler::DownloadResourceHandler( | 76 DownloadResourceHandler::DownloadResourceHandler( |
| 77 DownloadId id, |
| 76 net::URLRequest* request, | 78 net::URLRequest* request, |
| 77 const DownloadResourceHandler::OnStartedCallback& started_cb, | 79 const DownloadResourceHandler::OnStartedCallback& started_cb, |
| 78 scoped_ptr<DownloadSaveInfo> save_info) | 80 scoped_ptr<DownloadSaveInfo> save_info) |
| 79 : render_view_id_(0), // Actually initialized below. | 81 : download_id_(id), |
| 82 render_view_id_(0), // Actually initialized below. |
| 80 content_length_(0), | 83 content_length_(0), |
| 81 request_(request), | 84 request_(request), |
| 82 started_cb_(started_cb), | 85 started_cb_(started_cb), |
| 83 save_info_(save_info.Pass()), | 86 save_info_(save_info.Pass()), |
| 84 last_buffer_size_(0), | 87 last_buffer_size_(0), |
| 85 bytes_read_(0), | 88 bytes_read_(0), |
| 86 pause_count_(0), | 89 pause_count_(0), |
| 87 was_deferred_(false), | 90 was_deferred_(false), |
| 88 on_response_started_called_(false) { | 91 on_response_started_called_(false) { |
| 89 ResourceRequestInfoImpl* info(ResourceRequestInfoImpl::ForRequest(request)); | 92 ResourceRequestInfoImpl* info(ResourceRequestInfoImpl::ForRequest(request)); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 | 145 |
| 143 // Create the ByteStream for sending data to the download sink. | 146 // Create the ByteStream for sending data to the download sink. |
| 144 scoped_ptr<ByteStreamReader> stream_reader; | 147 scoped_ptr<ByteStreamReader> stream_reader; |
| 145 CreateByteStream( | 148 CreateByteStream( |
| 146 base::MessageLoopProxy::current(), | 149 base::MessageLoopProxy::current(), |
| 147 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), | 150 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), |
| 148 kDownloadByteStreamSize, &stream_writer_, &stream_reader); | 151 kDownloadByteStreamSize, &stream_writer_, &stream_reader); |
| 149 stream_writer_->RegisterCallback( | 152 stream_writer_->RegisterCallback( |
| 150 base::Bind(&DownloadResourceHandler::ResumeRequest, AsWeakPtr())); | 153 base::Bind(&DownloadResourceHandler::ResumeRequest, AsWeakPtr())); |
| 151 | 154 |
| 155 info->download_id = download_id_; |
| 152 info->url_chain = request_->url_chain(); | 156 info->url_chain = request_->url_chain(); |
| 153 info->referrer_url = GURL(request_->referrer()); | 157 info->referrer_url = GURL(request_->referrer()); |
| 154 info->start_time = base::Time::Now(); | 158 info->start_time = base::Time::Now(); |
| 155 info->total_bytes = content_length_; | 159 info->total_bytes = content_length_; |
| 156 info->has_user_gesture = request_info->HasUserGesture(); | 160 info->has_user_gesture = request_info->HasUserGesture(); |
| 157 info->content_disposition = content_disposition_; | 161 info->content_disposition = content_disposition_; |
| 158 info->mime_type = response->head.mime_type; | 162 info->mime_type = response->head.mime_type; |
| 159 info->remote_address = request_->GetSocketAddress().host(); | 163 info->remote_address = request_->GetSocketAddress().host(); |
| 160 RecordDownloadMimeType(info->mime_type); | 164 RecordDownloadMimeType(info->mime_type); |
| 161 RecordDownloadContentDisposition(info->content_disposition); | 165 RecordDownloadContentDisposition(info->content_disposition); |
| 162 | 166 |
| 163 info->request_handle = | 167 info->request_handle = |
| 164 DownloadRequestHandle(AsWeakPtr(), global_id_.child_id, | 168 DownloadRequestHandle(AsWeakPtr(), global_id_.child_id, |
| 165 render_view_id_, global_id_.request_id); | 169 render_view_id_, global_id_.request_id); |
| 166 | 170 |
| 167 // Get the last modified time and etag. | 171 // Get the last modified time and etag. |
| 168 const net::HttpResponseHeaders* headers = request_->response_headers(); | 172 const net::HttpResponseHeaders* headers = request_->response_headers(); |
| 169 if (headers) { | 173 if (headers) { |
| 170 std::string last_modified_hdr; | 174 std::string last_modified_hdr; |
| 171 std::string etag; | 175 std::string etag; |
| 172 if (headers->EnumerateHeader(NULL, "Last-Modified", &last_modified_hdr)) | 176 if (headers->EnumerateHeader(NULL, "Last-Modified", &last_modified_hdr)) |
| 173 info->last_modified = last_modified_hdr; | 177 info->last_modified = last_modified_hdr; |
| 174 if (headers->EnumerateHeader(NULL, "ETag", &etag)) | 178 if (headers->EnumerateHeader(NULL, "ETag", &etag)) |
| 175 info->etag = etag; | 179 info->etag = etag; |
| 180 |
| 181 int status = headers->response_code(); |
| 182 if (2 == status / 100 && status != net::HTTP_PARTIAL_CONTENT) { |
| 183 // Success & not range response; if we asked for a range, we didn't |
| 184 // get it--reset the file pointers to reflect that. |
| 185 save_info_->offset = 0; |
| 186 save_info_->hash_state = ""; |
| 187 } |
| 176 } | 188 } |
| 177 | 189 |
| 178 std::string content_type_header; | 190 std::string content_type_header; |
| 179 if (!response->head.headers || | 191 if (!response->head.headers || |
| 180 !response->head.headers->GetMimeType(&content_type_header)) | 192 !response->head.headers->GetMimeType(&content_type_header)) |
| 181 content_type_header = ""; | 193 content_type_header = ""; |
| 182 info->original_mime_type = content_type_header; | 194 info->original_mime_type = content_type_header; |
| 183 | 195 |
| 184 if (!response->head.headers || | 196 if (!response->head.headers || |
| 185 !response->head.headers->EnumerateHeader( | 197 !response->head.headers->EnumerateHeader( |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 *defer = was_deferred_ = true; | 287 *defer = was_deferred_ = true; |
| 276 | 288 |
| 277 return true; | 289 return true; |
| 278 } | 290 } |
| 279 | 291 |
| 280 bool DownloadResourceHandler::OnResponseCompleted( | 292 bool DownloadResourceHandler::OnResponseCompleted( |
| 281 int request_id, | 293 int request_id, |
| 282 const net::URLRequestStatus& status, | 294 const net::URLRequestStatus& status, |
| 283 const std::string& security_info) { | 295 const std::string& security_info) { |
| 284 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 296 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 297 int response_code = status.is_success() ? request_->GetResponseCode() : 0; |
| 285 VLOG(20) << __FUNCTION__ << "()" << DebugString() | 298 VLOG(20) << __FUNCTION__ << "()" << DebugString() |
| 286 << " request_id = " << request_id | 299 << " request_id = " << request_id |
| 287 << " status.status() = " << status.status() | 300 << " status.status() = " << status.status() |
| 288 << " status.error() = " << status.error(); | 301 << " status.error() = " << status.error() |
| 289 int response_code = status.is_success() ? request_->GetResponseCode() : 0; | 302 << " response_code = " << response_code; |
| 290 | 303 |
| 291 net::Error error_code = net::OK; | 304 net::Error error_code = net::OK; |
| 292 if (status.status() == net::URLRequestStatus::FAILED || | 305 if (status.status() == net::URLRequestStatus::FAILED || |
| 293 // Note cancels as failures too. | 306 // Note cancels as failures too. |
| 294 status.status() == net::URLRequestStatus::CANCELED) { | 307 status.status() == net::URLRequestStatus::CANCELED) { |
| 295 error_code = static_cast<net::Error>(status.error()); // Normal case. | 308 error_code = static_cast<net::Error>(status.error()); // Normal case. |
| 296 // Make sure that at least the fact of failure comes through. | 309 // Make sure that at least the fact of failure comes through. |
| 297 if (error_code == net::OK) | 310 if (error_code == net::OK) |
| 298 error_code = net::ERR_FAILED; | 311 error_code = net::ERR_FAILED; |
| 299 } | 312 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 316 // stack cancelled the request. There aren't that many things that | 329 // stack cancelled the request. There aren't that many things that |
| 317 // could do this to a download request (whose lifetime is separated from | 330 // could do this to a download request (whose lifetime is separated from |
| 318 // the tab from which it came). We map this to USER_CANCELLED as the | 331 // the tab from which it came). We map this to USER_CANCELLED as the |
| 319 // case we know about (system suspend because of laptop close) corresponds | 332 // case we know about (system suspend because of laptop close) corresponds |
| 320 // to a user action. | 333 // to a user action. |
| 321 // TODO(ahendrickson) -- Find a better set of codes to use here, as | 334 // TODO(ahendrickson) -- Find a better set of codes to use here, as |
| 322 // CANCELED/ERR_ABORTED can occur for reasons other than user cancel. | 335 // CANCELED/ERR_ABORTED can occur for reasons other than user cancel. |
| 323 reason = DOWNLOAD_INTERRUPT_REASON_USER_CANCELED; | 336 reason = DOWNLOAD_INTERRUPT_REASON_USER_CANCELED; |
| 324 } | 337 } |
| 325 | 338 |
| 326 if (status.is_success()) { | 339 if (status.is_success() && |
| 327 if (response_code >= 400) { | 340 reason == DOWNLOAD_INTERRUPT_REASON_NONE && |
| 328 switch(response_code) { | 341 request_->response_headers()) { |
| 329 case 404: // File Not Found. | 342 // Handle server's response codes. |
| 330 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT; | 343 switch(response_code) { |
| 331 break; | 344 case -1: // Non-HTTP request. |
| 332 case 416: // Range Not Satisfiable. | 345 case net::HTTP_OK: |
| 333 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE; | 346 case net::HTTP_PARTIAL_CONTENT: |
| 334 break; | 347 // Expected successful codes. |
| 335 case 412: // Precondition Failed. | 348 break; |
| 336 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION; | 349 case net::HTTP_NO_CONTENT: |
| 337 break; | 350 case net::HTTP_NOT_FOUND: |
| 338 default: | 351 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT; |
| 339 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED; | 352 break; |
| 340 break; | 353 case net::HTTP_PRECONDITION_FAILED: |
| 341 } | 354 // Failed our 'If-Unmodified-Since' or 'If-Match'; see |
| 355 // download_manager_impl.cc BeginDownload() |
| 356 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION; |
| 357 break; |
| 358 case net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: |
| 359 // Retry by downloading from the start automatically: |
| 360 // If we haven't received data when we get this error, we won't. |
| 361 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE; |
| 362 break; |
| 363 default: // All other errors. |
| 364 // Redirection should have been handled earlier in the stack. |
| 365 DCHECK(3 != response_code / 100); |
| 366 |
| 367 // Informational codes should have been handled earlier in the |
| 368 // stack. |
| 369 DCHECK(1 != response_code / 100); |
| 370 reason = DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED; |
| 371 break; |
| 342 } | 372 } |
| 343 } | 373 } |
| 344 | 374 |
| 345 RecordAcceptsRanges(accept_ranges_, bytes_read_); | 375 RecordAcceptsRanges(accept_ranges_, bytes_read_); |
| 346 RecordNetworkBlockage( | 376 RecordNetworkBlockage( |
| 347 base::TimeTicks::Now() - download_start_time_, total_pause_time_); | 377 base::TimeTicks::Now() - download_start_time_, total_pause_time_); |
| 348 | 378 |
| 349 CallStartedCB(NULL, error_code); | 379 CallStartedCB(NULL, error_code); |
| 350 | 380 |
| 351 // Send the info down the stream. Conditional is in case we get | 381 // Send the info down the stream. Conditional is in case we get |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 | 481 |
| 452 // Remove output stream callback if a stream exists. | 482 // Remove output stream callback if a stream exists. |
| 453 if (stream_writer_.get()) | 483 if (stream_writer_.get()) |
| 454 stream_writer_->RegisterCallback(base::Closure()); | 484 stream_writer_->RegisterCallback(base::Closure()); |
| 455 | 485 |
| 456 UMA_HISTOGRAM_TIMES("SB2.DownloadDuration", | 486 UMA_HISTOGRAM_TIMES("SB2.DownloadDuration", |
| 457 base::TimeTicks::Now() - download_start_time_); | 487 base::TimeTicks::Now() - download_start_time_); |
| 458 } | 488 } |
| 459 | 489 |
| 460 } // namespace content | 490 } // namespace content |
| OLD | NEW |