1 // Copyright 2013 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 "content/browser/loader/detachable_resource_handler.h" 6 7 #include "base/logging.h" 8 #include "base/time/time.h" 9 #include "content/browser/loader/resource_request_info_impl.h" 10 #include "net/base/io_buffer.h" 11 #include "net/base/net_errors.h" 12 #include "net/url_request/url_request_status.h" 13 14 namespace { 15 // This matches the maximum allocation size of AsyncResourceHandler. 16 const int kReadBufSize = 32 * 1024; 17 } 18 19 namespace content { 20 21 DetachableResourceHandler::DetachableResourceHandler( 22 net::URLRequest* request, 23 base::TimeDelta cancel_delay, 24 scoped_ptr<ResourceHandler> next_handler) 25 : ResourceHandler(request), 26 next_handler_(next_handler.Pass()), 27 cancel_delay_(cancel_delay), 28 is_deferred_(false), 29 is_finished_(false) { 30 GetRequestInfo()->set_detachable_handler(this); 31 } 32 33 DetachableResourceHandler::~DetachableResourceHandler() { 34 // Cleanup back-pointer stored on the request info. 35 GetRequestInfo()->set_detachable_handler(NULL); 36 } 37 38 void DetachableResourceHandler::Detach() { 39 if (is_detached()) 40 return; 41 42 if (!is_finished_) { 43 // Simulate a cancel on the next handler before destroying it. 44 net::URLRequestStatus status(net::URLRequestStatus::CANCELED, 45 net::ERR_ABORTED); 46 bool defer_ignored = false; 47 next_handler_->OnResponseCompleted(GetRequestID(), status, std::string(), 48 &defer_ignored); 49 DCHECK(!defer_ignored); 50 // If |next_handler_| were to defer its shutdown in OnResponseCompleted, 51 // this would destroy it anyway. Fortunately, AsyncResourceHandler never 52 // does this anyway, so DCHECK it. BufferedResourceHandler and RVH shutdown 53 // already ignore deferred ResourceHandler shutdown, but 54 // DetachableResourceHandler and the detach-on-renderer-cancel logic 55 // introduces a case where this occurs when the renderer cancels a resource. 56 } 57 // A OnWillRead / OnReadCompleted pair may still be in progress, but 58 // OnWillRead passes back a scoped_refptr, so downstream handler's buffer will 59 // survive long enough to complete that read. From there, future reads will 60 // drain into |read_buffer_|. (If |next_handler_| is an AsyncResourceHandler, 61 // the net::IOBuffer takes a reference to the ResourceBuffer which owns the 62 // shared memory.) 63 next_handler_.reset(); 64 65 // Time the request out if it takes too long. 66 detached_timer_.reset(new base::OneShotTimer<DetachableResourceHandler>()); 67 detached_timer_->Start( 68 FROM_HERE, cancel_delay_, this, &DetachableResourceHandler::Cancel); 69 70 // Resume if necessary. The request may have been deferred, say, waiting on a 71 // full buffer in AsyncResourceHandler. Now that it has been detached, resume 72 // and drain it. 73 if (is_deferred_) 74 Resume(); 75 } 76 77 void DetachableResourceHandler::SetController(ResourceController* controller) { 78 ResourceHandler::SetController(controller); 79 80 // Intercept the ResourceController for downstream handlers to keep track of 81 // whether the request is deferred. 82 if (next_handler_) 83 next_handler_->SetController(this); 84 } 85 86 bool DetachableResourceHandler::OnUploadProgress(int request_id, 87 uint64 position, 88 uint64 size) { 89 if (!next_handler_) 90 return true; 91 92 return next_handler_->OnUploadProgress(request_id, position, size); 93 } 94 95 bool DetachableResourceHandler::OnRequestRedirected(int request_id, 96 const GURL& url, 97 ResourceResponse* response, 98 bool* defer) { 99 DCHECK(!is_deferred_); 100 101 if (!next_handler_) 102 return true; 103 104 bool ret = next_handler_->OnRequestRedirected(request_id, url, response, 105 &is_deferred_); 106 *defer = is_deferred_; 107 return ret; 108 } 109 110 bool DetachableResourceHandler::OnResponseStarted(int request_id, 111 ResourceResponse* response, 112 bool* defer) { 113 DCHECK(!is_deferred_); 114 115 if (!next_handler_) 116 return true; 117 118 bool ret = 119 next_handler_->OnResponseStarted(request_id, response, &is_deferred_); 120 *defer = is_deferred_; 121 return ret; 122 } 123 124 bool DetachableResourceHandler::OnWillStart(int request_id, const GURL& url, 125 bool* defer) { 126 DCHECK(!is_deferred_); 127 128 if (!next_handler_) 129 return true; 130 131 bool ret = next_handler_->OnWillStart(request_id, url, &is_deferred_); 132 *defer = is_deferred_; 133 return ret; 134 } 135 136 bool DetachableResourceHandler::OnWillRead(int request_id, 137 scoped_refptr<net::IOBuffer>* buf, 138 int* buf_size, 139 int min_size) { 140 if (!next_handler_) { 141 DCHECK_EQ(-1, min_size); 142 if (!read_buffer_) 143 read_buffer_ = new net::IOBuffer(kReadBufSize); 144 *buf = read_buffer_; 145 *buf_size = kReadBufSize; 146 return true; 147 } 148 149 return next_handler_->OnWillRead(request_id, buf, buf_size, min_size); 150 } 151 152 bool DetachableResourceHandler::OnReadCompleted(int request_id, int bytes_read, 153 bool* defer) { 154 DCHECK(!is_deferred_); 155 156 if (!next_handler_) 157 return true; 158 159 bool ret = 160 next_handler_->OnReadCompleted(request_id, bytes_read, &is_deferred_); 161 *defer = is_deferred_; 162 return ret; 163 } 164 165 void DetachableResourceHandler::OnResponseCompleted( 166 int request_id, 167 const net::URLRequestStatus& status, 168 const std::string& security_info, 169 bool* defer) { 170 // No DCHECK(!is_deferred_) as the request may have been cancelled while 171 // deferred. 172 173 if (!next_handler_) 174 return; 175 176 is_finished_ = true; 177 178 next_handler_->OnResponseCompleted(request_id, status, security_info, 179 &is_deferred_); 180 *defer = is_deferred_; 181 } 182 183 void DetachableResourceHandler::OnDataDownloaded(int request_id, 184 int bytes_downloaded) { 185 if (!next_handler_) 186 return; 187 188 next_handler_->OnDataDownloaded(request_id, bytes_downloaded); 189 } 190 191 void DetachableResourceHandler::Resume() { 192 DCHECK(is_deferred_); 193 is_deferred_ = false; 194 controller()->Resume(); 195 } 196 197 void DetachableResourceHandler::Cancel() { 198 controller()->Cancel(); 199 } 200 201 void DetachableResourceHandler::CancelAndIgnore() { 202 controller()->CancelAndIgnore(); 203 } 204 205 void DetachableResourceHandler::CancelWithError(int error_code) { 206 controller()->CancelWithError(error_code); 207 } 208 209 } // namespace content 210