15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_resource_handler.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/stats_counters.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/byte_stream.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_create_info.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_interrupt_reasons_impl.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_manager_impl.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_request_handle.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/browser/download/download_stats.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/loader/resource_dispatcher_host_impl.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/loader/resource_request_info_impl.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_interrupt_reasons.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_item.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/download_manager_delegate.h" 27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/navigation_entry.h" 28a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "content/public/browser/power_save_blocker.h" 29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/web_contents.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/resource_response.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/http/http_response_headers.h" 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/http/http_status_code.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_context.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstruct DownloadResourceHandler::DownloadTabInfo { 40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch GURL tab_url; 41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch GURL tab_referrer_url; 42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}; 43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CallStartedCBOnUIThread( 477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const DownloadUrlParameters::OnStartedCallback& started_cb, 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DownloadItem* item, 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DownloadInterruptReason interrupt_reason) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (started_cb.is_null()) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) started_cb.Run(item, interrupt_reason); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Static function in order to prevent any accidental accesses to 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DownloadResourceHandler members from the UI thread. 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void StartOnUIThread( 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DownloadCreateInfo> info, 61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DownloadResourceHandler::DownloadTabInfo* tab_info, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<ByteStreamReader> stream, 637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const DownloadUrlParameters::OnStartedCallback& started_cb) { 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DownloadManager* download_manager = info->request_handle.GetDownloadManager(); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!download_manager) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // NULL in unittests or if the page closed right after starting the 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // download. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!started_cb.is_null()) 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) started_cb.Run(NULL, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // |stream| gets deleted on non-FILE thread, but it's ok since 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // we're not using stream_writer_ yet. 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch info->tab_url = tab_info->tab_url; 80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch info->tab_referrer_url = tab_info->tab_referrer_url; 81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch download_manager->StartDownload(info.Pass(), stream.Pass(), started_cb); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid InitializeDownloadTabInfoOnUIThread( 86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const DownloadRequestHandle& request_handle, 87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DownloadResourceHandler::DownloadTabInfo* tab_info) { 88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch WebContents* web_contents = request_handle.GetWebContents(); 91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (web_contents) { 92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch NavigationEntry* entry = web_contents->GetController().GetVisibleEntry(); 93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (entry) { 94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch tab_info->tab_url = entry->GetURL(); 95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch tab_info->tab_referrer_url = entry->GetReferrer().url; 96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 98effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 99effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int DownloadResourceHandler::kDownloadByteStreamSize = 100 * 1024; 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadResourceHandler::DownloadResourceHandler( 1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch uint32 id, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::URLRequest* request, 1077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch const DownloadUrlParameters::OnStartedCallback& started_cb, 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<DownloadSaveInfo> save_info) 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : ResourceHandler(request), 1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) download_id_(id), 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) started_cb_(started_cb), 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) save_info_(save_info.Pass()), 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_buffer_size_(0), 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes_read_(0), 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pause_count_(0), 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_deferred_(false), 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) on_response_started_called_(false) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RecordDownloadCount(UNTHROTTLED_COUNT); 119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Do UI thread initialization asap after DownloadResourceHandler creation 121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // since the tab could be navigated before StartOnUIThread gets called. 122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const ResourceRequestInfoImpl* request_info = GetRequestInfo(); 123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch tab_info_ = new DownloadTabInfo(); 124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch BrowserThread::PostTask( 125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch BrowserThread::UI, 126effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch FROM_HERE, 127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Bind(&InitializeDownloadTabInfoOnUIThread, 128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DownloadRequestHandle(AsWeakPtr(), 129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch request_info->GetChildID(), 130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch request_info->GetRouteID(), 131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch request_info->GetRequestID()), 132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch tab_info_)); 133a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch power_save_blocker_ = PowerSaveBlocker::Create( 134a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension, 135a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch "Download in progress"); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool DownloadResourceHandler::OnUploadProgress(uint64 position, 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint64 size) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadResourceHandler::OnRequestRedirected( 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GURL& url, 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResourceResponse* response, 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* defer) { 1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // We treat a download as a main frame load, and thus update the policy URL 1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // on redirects. 1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) request()->set_first_party_for_cookies(url); 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Send the download creation information to the download thread. 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DownloadResourceHandler::OnResponseStarted( 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResourceResponse* response, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* defer) { 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There can be only one (call) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!on_response_started_called_); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) on_response_started_called_ = true; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) VLOG(20) << __FUNCTION__ << "()" << DebugString(); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) download_start_time_ = base::TimeTicks::Now(); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If it's a download, we don't want to poison the cache with it. 1664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) request()->StopCaching(); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Lower priority as well, so downloads don't contend for resources 16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // with main frames. 1704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) request()->SetPriority(net::IDLE); 17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // If the content-length header is not present (or contains something other 173f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // than numbers), the incoming content_length is -1 (unknown size). 174f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Set the content length to 0 to indicate unknown size to DownloadManager. 175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) int64 content_length = 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) response->head.content_length > 0 ? response->head.content_length : 0; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const ResourceRequestInfoImpl* request_info = GetRequestInfo(); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Deleted in DownloadManager. 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_ptr<DownloadCreateInfo> info( 182f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) new DownloadCreateInfo(base::Time::Now(), 183f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) content_length, 184f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) request()->net_log(), 185f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) request_info->HasUserGesture(), 186f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) request_info->GetPageTransition(), 187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) save_info_.Pass())); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the ByteStream for sending data to the download sink. 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<ByteStreamReader> stream_reader; 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CreateByteStream( 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MessageLoopProxy::current(), 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kDownloadByteStreamSize, &stream_writer_, &stream_reader); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stream_writer_->RegisterCallback( 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&DownloadResourceHandler::ResumeRequest, AsWeakPtr())); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) info->download_id = download_id_; 1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) info->url_chain = request()->url_chain(); 2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) info->referrer_url = GURL(request()->referrer()); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->mime_type = response->head.mime_type; 2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) info->remote_address = request()->GetSocketAddress().host(); 203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) request()->GetResponseHeaderByName("content-disposition", 204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &info->content_disposition); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RecordDownloadMimeType(info->mime_type); 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RecordDownloadContentDisposition(info->content_disposition); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info->request_handle = 20968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) DownloadRequestHandle(AsWeakPtr(), request_info->GetChildID(), 21068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) request_info->GetRouteID(), 21168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) request_info->GetRequestID()); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the last modified time and etag. 2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const net::HttpResponseHeaders* headers = request()->response_headers(); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (headers) { 216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (headers->HasStrongValidators()) { 217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // If we don't have strong validators as per RFC 2616 section 13.3.3, then 218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // we neither store nor use them for range requests. 219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!headers->EnumerateHeader(NULL, "Last-Modified", 220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &info->last_modified)) 221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) info->last_modified.clear(); 222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!headers->EnumerateHeader(NULL, "ETag", &info->etag)) 223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) info->etag.clear(); 224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int status = headers->response_code(); 2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (2 == status / 100 && status != net::HTTP_PARTIAL_CONTENT) { 2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Success & not range response; if we asked for a range, we didn't 2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // get it--reset the file pointers to reflect that. 230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) info->save_info->offset = 0; 231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) info->save_info->hash_state = ""; 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (!headers->GetMimeType(&info->original_mime_type)) 235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) info->original_mime_type.clear(); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Blink verifies that the requester of this download is allowed to set a 2395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // suggested name for the security origin of the downlaod URL. However, this 2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // assumption doesn't hold if there were cross origin redirects. Therefore, 2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // clear the suggested_name for such requests. 2425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (info->url_chain.size() > 1 && 2435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu info->url_chain.front().GetOrigin() != info->url_chain.back().GetOrigin()) 2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu info->save_info->suggested_name.clear(); 2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::UI, FROM_HERE, 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&StartOnUIThread, 2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Passed(&info), 250effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Owned(tab_info_), 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Passed(&stream_reader), 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Pass to StartOnUIThread so that variable 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // access is always on IO thread but function 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is called on UI thread. 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) started_cb_)); 256effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Now owned by the task that was just posted. 257effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch tab_info_ = NULL; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Guaranteed to be called in StartOnUIThread 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) started_cb_.Reset(); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadResourceHandler::CallStartedCB( 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DownloadItem* item, 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DownloadInterruptReason interrupt_reason) { 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (started_cb_.is_null()) 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BrowserThread::PostTask( 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BrowserThread::UI, 2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind( 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &CallStartedCBOnUIThread, started_cb_, item, interrupt_reason)); 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) started_cb_.Reset(); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool DownloadResourceHandler::OnWillStart(const GURL& url, bool* defer) { 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool DownloadResourceHandler::OnBeforeNetworkStart(const GURL& url, 2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool* defer) { 2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Create a new buffer, which will be handed to the download thread for file 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// writing and deletion. 289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool DownloadResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, 2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int* buf_size, 2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int min_size) { 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(buf && buf_size); 294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!read_buffer_.get()); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *buf_size = min_size < 0 ? kReadBufSize : min_size; 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_buffer_size_ = *buf_size; 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_buffer_ = new net::IOBuffer(*buf_size); 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *buf = read_buffer_.get(); 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Pass the buffer to the download file writer. 304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool DownloadResourceHandler::OnReadCompleted(int bytes_read, bool* defer) { 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 306868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(read_buffer_.get()); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeTicks now(base::TimeTicks::Now()); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!last_read_time_.is_null()) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double seconds_since_last_read = (now - last_read_time_).InSecondsF(); 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (now == last_read_time_) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Use 1/10 ms as a "very small number" so that we avoid 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // divide-by-zero error and still record a very high potential bandwidth. 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) seconds_since_last_read = 0.00001; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double actual_bandwidth = (bytes_read)/seconds_since_last_read; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) double potential_bandwidth = last_buffer_size_/seconds_since_last_read; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RecordBandwidth(actual_bandwidth, potential_bandwidth); 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_read_time_ = now; 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!bytes_read) 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes_read_ += bytes_read; 325868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(read_buffer_.get()); 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Take the data ship it down the stream. If the stream is full, pause the 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // request; the stream callback will resume it. 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!stream_writer_->Write(read_buffer_, bytes_read)) { 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PauseRequest(); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *defer = was_deferred_ = true; 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_stream_pause_time_ = now; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_buffer_ = NULL; // Drop our reference. 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pause_count_ > 0) 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *defer = was_deferred_ = true; 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 343f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void DownloadResourceHandler::OnResponseCompleted( 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status, 345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string& security_info, 346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool* defer) { 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 3484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int response_code = status.is_success() ? request()->GetResponseCode() : 0; 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VLOG(20) << __FUNCTION__ << "()" << DebugString() 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " status.status() = " << status.status() 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << " status.error() = " << status.error() 3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << " response_code = " << response_code; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) net::Error error_code = net::OK; 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status.status() == net::URLRequestStatus::FAILED || 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note cancels as failures too. 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status.status() == net::URLRequestStatus::CANCELED) { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_code = static_cast<net::Error>(status.error()); // Normal case. 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure that at least the fact of failure comes through. 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (error_code == net::OK) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_code = net::ERR_FAILED; 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ERR_CONTENT_LENGTH_MISMATCH and ERR_INCOMPLETE_CHUNKED_ENCODING are 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allowed since a number of servers in the wild close the connection too 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // early by mistake. Other browsers - IE9, Firefox 11.0, and Safari 5.1.4 - 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // treat downloads as complete in both cases, so we follow their lead. 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (error_code == net::ERR_CONTENT_LENGTH_MISMATCH || 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_code == net::ERR_INCOMPLETE_CHUNKED_ENCODING) { 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_code = net::OK; 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DownloadInterruptReason reason = 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertNetErrorToInterruptReason( 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_code, DOWNLOAD_INTERRUPT_FROM_NETWORK); 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (status.status() == net::URLRequestStatus::CANCELED && 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) status.error() == net::ERR_ABORTED) { 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CANCELED + ERR_ABORTED == something outside of the network 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // stack cancelled the request. There aren't that many things that 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // could do this to a download request (whose lifetime is separated from 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the tab from which it came). We map this to USER_CANCELLED as the 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // case we know about (system suspend because of laptop close) corresponds 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to a user action. 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(ahendrickson) -- Find a better set of codes to use here, as 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // CANCELED/ERR_ABORTED can occur for reasons other than user cancel. 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reason = DOWNLOAD_INTERRUPT_REASON_USER_CANCELED; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (status.is_success() && 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reason == DOWNLOAD_INTERRUPT_REASON_NONE && 3914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) request()->response_headers()) { 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Handle server's response codes. 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch(response_code) { 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case -1: // Non-HTTP request. 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case net::HTTP_OK: 3967d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) case net::HTTP_CREATED: 3977d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) case net::HTTP_ACCEPTED: 3987d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) case net::HTTP_NON_AUTHORITATIVE_INFORMATION: 3997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) case net::HTTP_RESET_CONTENT: 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case net::HTTP_PARTIAL_CONTENT: 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Expected successful codes. 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case net::HTTP_NO_CONTENT: 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case net::HTTP_NOT_FOUND: 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reason = DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT; 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case net::HTTP_PRECONDITION_FAILED: 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Failed our 'If-Unmodified-Since' or 'If-Match'; see 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // download_manager_impl.cc BeginDownload() 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reason = DOWNLOAD_INTERRUPT_REASON_SERVER_PRECONDITION; 4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE: 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Retry by downloading from the start automatically: 4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If we haven't received data when we get this error, we won't. 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reason = DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE; 4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) default: // All other errors. 4187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // Redirection and informational codes should have been handled earlier 4197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) // in the stack. 4207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK_NE(3, response_code / 100); 4217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) DCHECK_NE(1, response_code / 100); 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reason = DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED; 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 427f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) std::string accept_ranges; 428f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool has_strong_validators = false; 429f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if (request()->response_headers()) { 430f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) request()->response_headers()->EnumerateHeader( 431f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) NULL, "Accept-Ranges", &accept_ranges); 432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) has_strong_validators = 433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) request()->response_headers()->HasStrongValidators(); 434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 435f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RecordAcceptsRanges(accept_ranges, bytes_read_, has_strong_validators); 436f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) RecordNetworkBlockage(base::TimeTicks::Now() - download_start_time_, 437f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) total_pause_time_); 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CallStartedCB(NULL, reason); 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Send the info down the stream. Conditional is in case we get 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // OnResponseCompleted without OnResponseStarted. 443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (stream_writer_) 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stream_writer_->Close(reason); 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the error mapped to something unknown, record it so that 4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // we can drill down. 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (reason == DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED) { 4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_CUSTOM_ENUMERATION("Download.MapErrorNetworkFailed", 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::abs(status.error()), 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) net::GetAllErrorCodesForUma()); 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stream_writer_.reset(); // We no longer need the stream. 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_buffer_ = NULL; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 458cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DownloadResourceHandler::OnDataDownloaded(int bytes_downloaded) { 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadResourceHandler::PauseRequest() { 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++pause_count_; 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadResourceHandler::ResumeRequest() { 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(0, pause_count_); 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --pause_count_; 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!was_deferred_) 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pause_count_ > 0) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) was_deferred_ = false; 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!last_stream_pause_time_.is_null()) { 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) total_pause_time_ += (base::TimeTicks::Now() - last_stream_pause_time_); 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_stream_pause_time_ = base::TimeTicks(); 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller()->Resume(); 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DownloadResourceHandler::CancelRequest() { 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const ResourceRequestInfo* info = GetRequestInfo(); 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResourceDispatcherHostImpl::Get()->CancelRequest( 49368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) info->GetChildID(), 4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) info->GetRequestID()); 4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // This object has been deleted. 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string DownloadResourceHandler::DebugString() const { 4994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) const ResourceRequestInfo* info = GetRequestInfo(); 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return base::StringPrintf("{" 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " url_ = " "\"%s\"" 50268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) " info = {" 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " child_id = " "%d" 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " request_id = " "%d" 50568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) " route_id = " "%d" 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " }" 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) " }", 5084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) request() ? 5094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) request()->url().spec().c_str() : 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "<NULL request>", 51168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) info->GetChildID(), 51268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) info->GetRequestID(), 51368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) info->GetRouteID()); 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DownloadResourceHandler::~DownloadResourceHandler() { 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This won't do anything if the callback was called before. 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If it goes through, it will likely be because OnWillStart() returned 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // false somewhere in the chain of resource handlers. 5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CallStartedCB(NULL, DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED); 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Remove output stream callback if a stream exists. 525c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (stream_writer_) 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stream_writer_->RegisterCallback(base::Closure()); 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 528effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // tab_info_ must be destroyed on UI thread, since 529effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // InitializeDownloadTabInfoOnUIThread might still be using it. 530effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (tab_info_) 531effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, tab_info_); 532effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_TIMES("SB2.DownloadDuration", 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::TimeTicks::Now() - download_start_time_); 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 538