Home | History | Annotate | Download | only in renderer_host
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/renderer_host/download_resource_handler.h"
      6 
      7 #include <string>
      8 
      9 #include "base/logging.h"
     10 #include "base/metrics/histogram.h"
     11 #include "base/metrics/stats_counters.h"
     12 #include "base/stringprintf.h"
     13 #include "chrome/browser/download/download_item.h"
     14 #include "chrome/browser/download/download_file_manager.h"
     15 #include "chrome/browser/download/download_util.h"
     16 #include "chrome/browser/history/download_create_info.h"
     17 #include "content/browser/browser_thread.h"
     18 #include "content/browser/renderer_host/global_request_id.h"
     19 #include "content/browser/renderer_host/resource_dispatcher_host.h"
     20 #include "content/browser/renderer_host/resource_dispatcher_host_request_info.h"
     21 #include "content/common/resource_response.h"
     22 #include "net/base/io_buffer.h"
     23 #include "net/http/http_response_headers.h"
     24 #include "net/url_request/url_request_context.h"
     25 
     26 DownloadResourceHandler::DownloadResourceHandler(
     27     ResourceDispatcherHost* rdh,
     28     int render_process_host_id,
     29     int render_view_id,
     30     int request_id,
     31     const GURL& url,
     32     DownloadFileManager* download_file_manager,
     33     net::URLRequest* request,
     34     bool save_as,
     35     const DownloadSaveInfo& save_info)
     36     : download_id_(-1),
     37       global_id_(render_process_host_id, request_id),
     38       render_view_id_(render_view_id),
     39       content_length_(0),
     40       download_file_manager_(download_file_manager),
     41       request_(request),
     42       save_as_(save_as),
     43       save_info_(save_info),
     44       buffer_(new DownloadBuffer),
     45       rdh_(rdh),
     46       is_paused_(false) {
     47   download_util::RecordDownloadCount(download_util::UNTHROTTLED_COUNT);
     48 }
     49 
     50 bool DownloadResourceHandler::OnUploadProgress(int request_id,
     51                                                uint64 position,
     52                                                uint64 size) {
     53   return true;
     54 }
     55 
     56 // Not needed, as this event handler ought to be the final resource.
     57 bool DownloadResourceHandler::OnRequestRedirected(int request_id,
     58                                                   const GURL& url,
     59                                                   ResourceResponse* response,
     60                                                   bool* defer) {
     61   return true;
     62 }
     63 
     64 // Send the download creation information to the download thread.
     65 bool DownloadResourceHandler::OnResponseStarted(int request_id,
     66                                                 ResourceResponse* response) {
     67   VLOG(20) << __FUNCTION__ << "()" << DebugString()
     68            << " request_id = " << request_id;
     69   download_start_time_ = base::TimeTicks::Now();
     70   std::string content_disposition;
     71   request_->GetResponseHeaderByName("content-disposition",
     72                                     &content_disposition);
     73   set_content_disposition(content_disposition);
     74   set_content_length(response->response_head.content_length);
     75 
     76   const ResourceDispatcherHostRequestInfo* request_info =
     77     ResourceDispatcherHost::InfoForRequest(request_);
     78 
     79   download_id_ = download_file_manager_->GetNextId();
     80 
     81   // Deleted in DownloadManager.
     82   DownloadCreateInfo* info = new DownloadCreateInfo;
     83   info->url_chain = request_->url_chain();
     84   info->referrer_url = GURL(request_->referrer());
     85   info->start_time = base::Time::Now();
     86   info->received_bytes = 0;
     87   info->total_bytes = content_length_;
     88   info->state = DownloadItem::IN_PROGRESS;
     89   info->download_id = download_id_;
     90   info->has_user_gesture = request_info->has_user_gesture();
     91   info->child_id = global_id_.child_id;
     92   info->render_view_id = render_view_id_;
     93   info->request_id = global_id_.request_id;
     94   info->content_disposition = content_disposition_;
     95   info->mime_type = response->response_head.mime_type;
     96   // TODO(ahendrickson) -- Get the last modified time and etag, so we can
     97   // resume downloading.
     98 
     99   std::string content_type_header;
    100   if (!response->response_head.headers ||
    101       !response->response_head.headers->GetMimeType(&content_type_header))
    102     content_type_header = "";
    103   info->original_mime_type = content_type_header;
    104 
    105   info->prompt_user_for_save_location =
    106       save_as_ && save_info_.file_path.empty();
    107   info->is_dangerous_file = false;
    108   info->is_dangerous_url = false;
    109   info->referrer_charset = request_->context()->referrer_charset();
    110   info->save_info = save_info_;
    111   BrowserThread::PostTask(
    112       BrowserThread::UI, FROM_HERE,
    113       NewRunnableMethod(
    114           download_file_manager_, &DownloadFileManager::StartDownload, info));
    115 
    116   // We can't start saving the data before we create the file on disk.
    117   // The request will be un-paused in DownloadFileManager::CreateDownloadFile.
    118   rdh_->PauseRequest(global_id_.child_id, global_id_.request_id, true);
    119 
    120   return true;
    121 }
    122 
    123 bool DownloadResourceHandler::OnWillStart(int request_id,
    124                                           const GURL& url,
    125                                           bool* defer) {
    126   return true;
    127 }
    128 
    129 // Create a new buffer, which will be handed to the download thread for file
    130 // writing and deletion.
    131 bool DownloadResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
    132                                          int* buf_size, int min_size) {
    133   DCHECK(buf && buf_size);
    134   if (!read_buffer_) {
    135     *buf_size = min_size < 0 ? kReadBufSize : min_size;
    136     read_buffer_ = new net::IOBuffer(*buf_size);
    137   }
    138   *buf = read_buffer_.get();
    139   return true;
    140 }
    141 
    142 // Pass the buffer to the download file writer.
    143 bool DownloadResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
    144   if (!*bytes_read)
    145     return true;
    146   DCHECK(read_buffer_);
    147   base::AutoLock auto_lock(buffer_->lock);
    148   bool need_update = buffer_->contents.empty();
    149 
    150   // We are passing ownership of this buffer to the download file manager.
    151   net::IOBuffer* buffer = NULL;
    152   read_buffer_.swap(&buffer);
    153   buffer_->contents.push_back(std::make_pair(buffer, *bytes_read));
    154   if (need_update) {
    155     BrowserThread::PostTask(
    156         BrowserThread::FILE, FROM_HERE,
    157         NewRunnableMethod(download_file_manager_,
    158                           &DownloadFileManager::UpdateDownload,
    159                           download_id_,
    160                           buffer_.get()));
    161   }
    162 
    163   // We schedule a pause outside of the read loop if there is too much file
    164   // writing work to do.
    165   if (buffer_->contents.size() > kLoadsToWrite)
    166     StartPauseTimer();
    167 
    168   return true;
    169 }
    170 
    171 bool DownloadResourceHandler::OnResponseCompleted(
    172     int request_id,
    173     const net::URLRequestStatus& status,
    174     const std::string& security_info) {
    175   VLOG(20) << __FUNCTION__ << "()" << DebugString()
    176            << " request_id = " << request_id
    177            << " status.status() = " << status.status()
    178            << " status.os_error() = " << status.os_error();
    179   int error_code = (status.status() == net::URLRequestStatus::FAILED) ?
    180       status.os_error() : 0;
    181   // We transfer ownership to |DownloadFileManager| to delete |buffer_|,
    182   // so that any functions queued up on the FILE thread are executed
    183   // before deletion.
    184   BrowserThread::PostTask(
    185       BrowserThread::FILE, FROM_HERE,
    186       NewRunnableMethod(download_file_manager_,
    187                         &DownloadFileManager::OnResponseCompleted,
    188                         download_id_,
    189                         buffer_.release(),
    190                         error_code,
    191                         security_info));
    192   read_buffer_ = NULL;
    193   return true;
    194 }
    195 
    196 void DownloadResourceHandler::OnRequestClosed() {
    197   UMA_HISTOGRAM_TIMES("SB2.DownloadDuration",
    198                       base::TimeTicks::Now() - download_start_time_);
    199 }
    200 
    201 // If the content-length header is not present (or contains something other
    202 // than numbers), the incoming content_length is -1 (unknown size).
    203 // Set the content length to 0 to indicate unknown size to DownloadManager.
    204 void DownloadResourceHandler::set_content_length(const int64& content_length) {
    205   content_length_ = 0;
    206   if (content_length > 0)
    207     content_length_ = content_length;
    208 }
    209 
    210 void DownloadResourceHandler::set_content_disposition(
    211     const std::string& content_disposition) {
    212   content_disposition_ = content_disposition;
    213 }
    214 
    215 void DownloadResourceHandler::CheckWriteProgress() {
    216   if (!buffer_.get())
    217     return;  // The download completed while we were waiting to run.
    218 
    219   size_t contents_size;
    220   {
    221     base::AutoLock lock(buffer_->lock);
    222     contents_size = buffer_->contents.size();
    223   }
    224 
    225   bool should_pause = contents_size > kLoadsToWrite;
    226 
    227   // We'll come back later and see if it's okay to unpause the request.
    228   if (should_pause)
    229     StartPauseTimer();
    230 
    231   if (is_paused_ != should_pause) {
    232     rdh_->PauseRequest(global_id_.child_id, global_id_.request_id,
    233                        should_pause);
    234     is_paused_ = should_pause;
    235   }
    236 }
    237 
    238 DownloadResourceHandler::~DownloadResourceHandler() {
    239 }
    240 
    241 void DownloadResourceHandler::StartPauseTimer() {
    242   if (!pause_timer_.IsRunning())
    243     pause_timer_.Start(base::TimeDelta::FromMilliseconds(kThrottleTimeMs), this,
    244                        &DownloadResourceHandler::CheckWriteProgress);
    245 }
    246 
    247 std::string DownloadResourceHandler::DebugString() const {
    248   return base::StringPrintf("{"
    249                             " url_ = " "\"%s\""
    250                             " download_id_ = " "%d"
    251                             " global_id_ = {"
    252                             " child_id = " "%d"
    253                             " request_id = " "%d"
    254                             " }"
    255                             " render_view_id_ = " "%d"
    256                             " save_info_.file_path = \"%" PRFilePath "\""
    257                             " }",
    258                             request_->url().spec().c_str(),
    259                             download_id_,
    260                             global_id_.child_id,
    261                             global_id_.request_id,
    262                             render_view_id_,
    263                             save_info_.file_path.value().c_str());
    264 }
    265