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_throttling_resource_handler.h" 6 7 #include "base/logging.h" 8 #include "chrome/browser/download/download_util.h" 9 #include "chrome/browser/renderer_host/download_resource_handler.h" 10 #include "content/browser/renderer_host/resource_dispatcher_host.h" 11 #include "content/common/resource_response.h" 12 #include "net/base/io_buffer.h" 13 #include "net/base/mime_sniffer.h" 14 15 DownloadThrottlingResourceHandler::DownloadThrottlingResourceHandler( 16 ResourceDispatcherHost* host, 17 net::URLRequest* request, 18 const GURL& url, 19 int render_process_host_id, 20 int render_view_id, 21 int request_id, 22 bool in_complete) 23 : host_(host), 24 request_(request), 25 url_(url), 26 render_process_host_id_(render_process_host_id), 27 render_view_id_(render_view_id), 28 request_id_(request_id), 29 tmp_buffer_length_(0), 30 ignore_on_read_complete_(in_complete), 31 request_closed_(false) { 32 download_util::RecordDownloadCount( 33 download_util::INITIATED_BY_NAVIGATION_COUNT); 34 35 // Pause the request. 36 host_->PauseRequest(render_process_host_id_, request_id_, true); 37 38 // Add a reference to ourselves to keep this object alive until we 39 // receive a callback from DownloadRequestLimiter. The reference is 40 // released in ContinueDownload() and CancelDownload(). 41 AddRef(); 42 43 host_->download_request_limiter()->CanDownloadOnIOThread( 44 render_process_host_id_, render_view_id, request_id, this); 45 BrowserThread::PostTask( 46 BrowserThread::UI, FROM_HERE, 47 NewRunnableFunction(&download_util::NotifyDownloadInitiated, 48 render_process_host_id_, render_view_id_)); 49 } 50 51 DownloadThrottlingResourceHandler::~DownloadThrottlingResourceHandler() { 52 } 53 54 bool DownloadThrottlingResourceHandler::OnUploadProgress(int request_id, 55 uint64 position, 56 uint64 size) { 57 DCHECK(!request_closed_); 58 if (download_handler_.get()) 59 return download_handler_->OnUploadProgress(request_id, position, size); 60 return true; 61 } 62 63 bool DownloadThrottlingResourceHandler::OnRequestRedirected( 64 int request_id, 65 const GURL& url, 66 ResourceResponse* response, 67 bool* defer) { 68 DCHECK(!request_closed_); 69 if (download_handler_.get()) { 70 return download_handler_->OnRequestRedirected( 71 request_id, url, response, defer); 72 } 73 url_ = url; 74 return true; 75 } 76 77 bool DownloadThrottlingResourceHandler::OnResponseStarted( 78 int request_id, 79 ResourceResponse* response) { 80 DCHECK(!request_closed_); 81 if (download_handler_.get()) 82 return download_handler_->OnResponseStarted(request_id, response); 83 response_ = response; 84 return true; 85 } 86 87 bool DownloadThrottlingResourceHandler::OnWillStart(int request_id, 88 const GURL& url, 89 bool* defer) { 90 DCHECK(!request_closed_); 91 if (download_handler_.get()) 92 return download_handler_->OnWillStart(request_id, url, defer); 93 return true; 94 } 95 96 bool DownloadThrottlingResourceHandler::OnWillRead(int request_id, 97 net::IOBuffer** buf, 98 int* buf_size, 99 int min_size) { 100 DCHECK(!request_closed_); 101 if (download_handler_.get()) 102 return download_handler_->OnWillRead(request_id, buf, buf_size, min_size); 103 104 // We should only have this invoked once, as such we only deal with one 105 // tmp buffer. 106 DCHECK(!tmp_buffer_.get()); 107 // If the caller passed a negative |min_size| then chose an appropriate 108 // default. The BufferedResourceHandler requires this to be at least 2 times 109 // the size required for mime detection. 110 if (min_size < 0) 111 min_size = 2 * net::kMaxBytesToSniff; 112 tmp_buffer_ = new net::IOBuffer(min_size); 113 *buf = tmp_buffer_.get(); 114 *buf_size = min_size; 115 return true; 116 } 117 118 bool DownloadThrottlingResourceHandler::OnReadCompleted(int request_id, 119 int* bytes_read) { 120 DCHECK(!request_closed_); 121 if (ignore_on_read_complete_) { 122 // See comments above definition for details on this. 123 ignore_on_read_complete_ = false; 124 return true; 125 } 126 if (!*bytes_read) 127 return true; 128 129 if (tmp_buffer_.get()) { 130 DCHECK(!tmp_buffer_length_); 131 tmp_buffer_length_ = *bytes_read; 132 if (download_handler_.get()) 133 CopyTmpBufferToDownloadHandler(); 134 return true; 135 } 136 if (download_handler_.get()) 137 return download_handler_->OnReadCompleted(request_id, bytes_read); 138 return true; 139 } 140 141 bool DownloadThrottlingResourceHandler::OnResponseCompleted( 142 int request_id, 143 const net::URLRequestStatus& status, 144 const std::string& security_info) { 145 DCHECK(!request_closed_); 146 if (download_handler_.get()) 147 return download_handler_->OnResponseCompleted(request_id, status, 148 security_info); 149 150 // For a download, if ResourceDispatcher::Read() fails, 151 // ResourceDispatcher::OnresponseStarted() will call 152 // OnResponseCompleted(), and we will end up here with an error 153 // status. 154 if (!status.is_success()) 155 return false; 156 NOTREACHED(); 157 return true; 158 } 159 160 void DownloadThrottlingResourceHandler::OnRequestClosed() { 161 DCHECK(!request_closed_); 162 if (download_handler_.get()) 163 download_handler_->OnRequestClosed(); 164 request_closed_ = true; 165 } 166 167 void DownloadThrottlingResourceHandler::CancelDownload() { 168 if (!request_closed_) 169 host_->CancelRequest(render_process_host_id_, request_id_, false); 170 Release(); // Release the additional reference from constructor. 171 } 172 173 void DownloadThrottlingResourceHandler::ContinueDownload() { 174 DCHECK(!download_handler_.get()); 175 if (!request_closed_) { 176 download_handler_ = 177 new DownloadResourceHandler(host_, 178 render_process_host_id_, 179 render_view_id_, 180 request_id_, 181 url_, 182 host_->download_file_manager(), 183 request_, 184 false, 185 DownloadSaveInfo()); 186 if (response_.get()) 187 download_handler_->OnResponseStarted(request_id_, response_.get()); 188 189 if (tmp_buffer_length_) 190 CopyTmpBufferToDownloadHandler(); 191 192 // And let the request continue. 193 host_->PauseRequest(render_process_host_id_, request_id_, false); 194 } 195 Release(); // Release the addtional reference from constructor. 196 } 197 198 void DownloadThrottlingResourceHandler::CopyTmpBufferToDownloadHandler() { 199 // Copy over the tmp buffer. 200 net::IOBuffer* buffer; 201 int buf_size; 202 if (download_handler_->OnWillRead(request_id_, &buffer, &buf_size, 203 tmp_buffer_length_)) { 204 CHECK(buf_size >= tmp_buffer_length_); 205 memcpy(buffer->data(), tmp_buffer_->data(), tmp_buffer_length_); 206 download_handler_->OnReadCompleted(request_id_, &tmp_buffer_length_); 207 } 208 tmp_buffer_length_ = 0; 209 tmp_buffer_ = NULL; 210 } 211