• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DownloadThrottlingResourceHandler(ResourceDispatcherHost * host,net::URLRequest * request,const GURL & url,int render_process_host_id,int render_view_id,int request_id,bool in_complete)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 
~DownloadThrottlingResourceHandler()51 DownloadThrottlingResourceHandler::~DownloadThrottlingResourceHandler() {
52 }
53 
OnUploadProgress(int request_id,uint64 position,uint64 size)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 
OnRequestRedirected(int request_id,const GURL & url,ResourceResponse * response,bool * defer)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 
OnResponseStarted(int request_id,ResourceResponse * response)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 
OnWillStart(int request_id,const GURL & url,bool * defer)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 
OnWillRead(int request_id,net::IOBuffer ** buf,int * buf_size,int min_size)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 
OnReadCompleted(int request_id,int * bytes_read)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 
OnResponseCompleted(int request_id,const net::URLRequestStatus & status,const std::string & security_info)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 
OnRequestClosed()160 void DownloadThrottlingResourceHandler::OnRequestClosed() {
161   DCHECK(!request_closed_);
162   if (download_handler_.get())
163     download_handler_->OnRequestClosed();
164   request_closed_ = true;
165 }
166 
CancelDownload()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 
ContinueDownload()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 
CopyTmpBufferToDownloadHandler()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