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