| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/async_resource_handler.h" | 5 #include "content/browser/renderer_host/async_resource_handler.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/debug/alias.h" | 10 #include "base/debug/alias.h" |
| 11 #include "base/hash_tables.h" | 11 #include "base/hash_tables.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/shared_memory.h" | 13 #include "base/shared_memory.h" |
| 14 #include "content/browser/debugger/devtools_netlog_observer.h" | 14 #include "content/browser/debugger/devtools_netlog_observer.h" |
| 15 #include "content/browser/host_zoom_map_impl.h" | 15 #include "content/browser/host_zoom_map_impl.h" |
| 16 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h" | 16 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h" |
| 17 #include "content/browser/renderer_host/resource_message_filter.h" | 17 #include "content/browser/renderer_host/resource_message_filter.h" |
| 18 #include "content/browser/renderer_host/resource_request_info_impl.h" |
| 18 #include "content/browser/resource_context_impl.h" | 19 #include "content/browser/resource_context_impl.h" |
| 19 #include "content/common/resource_messages.h" | 20 #include "content/common/resource_messages.h" |
| 20 #include "content/common/view_messages.h" | 21 #include "content/common/view_messages.h" |
| 21 #include "content/public/browser/global_request_id.h" | 22 #include "content/public/browser/global_request_id.h" |
| 22 #include "content/public/browser/resource_dispatcher_host_delegate.h" | 23 #include "content/public/browser/resource_dispatcher_host_delegate.h" |
| 23 #include "content/public/browser/resource_request_info.h" | |
| 24 #include "content/public/common/resource_response.h" | 24 #include "content/public/common/resource_response.h" |
| 25 #include "net/base/io_buffer.h" | 25 #include "net/base/io_buffer.h" |
| 26 #include "net/base/load_flags.h" | 26 #include "net/base/load_flags.h" |
| 27 #include "net/base/net_log.h" | 27 #include "net/base/net_log.h" |
| 28 #include "webkit/glue/resource_loader_bridge.h" | 28 #include "webkit/glue/resource_loader_bridge.h" |
| 29 | 29 |
| 30 using base::TimeTicks; | 30 using base::TimeTicks; |
| 31 | 31 |
| 32 namespace content { | 32 namespace content { |
| 33 | 33 |
| 34 namespace { | 34 namespace { |
| 35 | 35 |
| 36 // When reading, we don't know if we are going to get EOF (0 bytes read), so | 36 // When reading, we don't know if we are going to get EOF (0 bytes read), so |
| 37 // we typically have a buffer that we allocated but did not use. We keep | 37 // we typically have a buffer that we allocated but did not use. We keep |
| 38 // this buffer around for the next read as a small optimization. | 38 // this buffer around for the next read as a small optimization. |
| 39 SharedIOBuffer* g_spare_read_buffer = NULL; | 39 SharedIOBuffer* g_spare_read_buffer = NULL; |
| 40 | 40 |
| 41 // The initial size of the shared memory buffer. (32 kilobytes). | 41 // The initial size of the shared memory buffer. (32 kilobytes). |
| 42 const int kInitialReadBufSize = 32768; | 42 const int kInitialReadBufSize = 32768; |
| 43 | 43 |
| 44 // The maximum size of the shared memory buffer. (512 kilobytes). | 44 // The maximum size of the shared memory buffer. (512 kilobytes). |
| 45 const int kMaxReadBufSize = 524288; | 45 const int kMaxReadBufSize = 524288; |
| 46 | 46 |
| 47 // Maximum number of pending data messages sent to the renderer at any |
| 48 // given time for a given request. |
| 49 const int kMaxPendingDataMessages = 20; |
| 50 |
| 47 } // namespace | 51 } // namespace |
| 48 | 52 |
| 49 // Our version of IOBuffer that uses shared memory. | 53 // Our version of IOBuffer that uses shared memory. |
| 50 class SharedIOBuffer : public net::IOBuffer { | 54 class SharedIOBuffer : public net::IOBuffer { |
| 51 public: | 55 public: |
| 52 explicit SharedIOBuffer(int buffer_size) | 56 explicit SharedIOBuffer(int buffer_size) |
| 53 : net::IOBuffer(), | 57 : net::IOBuffer(), |
| 54 ok_(false), | 58 ok_(false), |
| 55 buffer_size_(buffer_size) {} | 59 buffer_size_(buffer_size) {} |
| 56 | 60 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 74 } | 78 } |
| 75 | 79 |
| 76 base::SharedMemory shared_memory_; | 80 base::SharedMemory shared_memory_; |
| 77 bool ok_; | 81 bool ok_; |
| 78 int buffer_size_; | 82 int buffer_size_; |
| 79 }; | 83 }; |
| 80 | 84 |
| 81 AsyncResourceHandler::AsyncResourceHandler( | 85 AsyncResourceHandler::AsyncResourceHandler( |
| 82 ResourceMessageFilter* filter, | 86 ResourceMessageFilter* filter, |
| 83 int routing_id, | 87 int routing_id, |
| 84 const GURL& url, | 88 net::URLRequest* request, |
| 85 ResourceDispatcherHostImpl* rdh) | 89 ResourceDispatcherHostImpl* rdh) |
| 86 : filter_(filter), | 90 : filter_(filter), |
| 87 routing_id_(routing_id), | 91 routing_id_(routing_id), |
| 92 request_(request), |
| 88 rdh_(rdh), | 93 rdh_(rdh), |
| 89 next_buffer_size_(kInitialReadBufSize), | 94 next_buffer_size_(kInitialReadBufSize), |
| 90 url_(url) { | 95 pending_data_count_(0), |
| 96 did_defer_(false) { |
| 97 // Set a back-pointer from ResourceRequestInfoImpl to |this|, so that the |
| 98 // ResourceDispatcherHostImpl can send us IPC messages. |
| 99 // TODO(darin): Implement an IPC message filter instead? |
| 100 ResourceRequestInfoImpl::ForRequest(request_)->set_async_handler(this); |
| 91 } | 101 } |
| 92 | 102 |
| 93 AsyncResourceHandler::~AsyncResourceHandler() { | 103 AsyncResourceHandler::~AsyncResourceHandler() { |
| 104 // Cleanup back-pointer stored on the request info. |
| 105 ResourceRequestInfoImpl::ForRequest(request_)->set_async_handler(NULL); |
| 106 } |
| 107 |
| 108 void AsyncResourceHandler::OnFollowRedirect( |
| 109 bool has_new_first_party_for_cookies, |
| 110 const GURL& new_first_party_for_cookies) { |
| 111 if (!request_->status().is_success()) { |
| 112 DVLOG(1) << "OnFollowRedirect for invalid request"; |
| 113 return; |
| 114 } |
| 115 |
| 116 if (has_new_first_party_for_cookies) |
| 117 request_->set_first_party_for_cookies(new_first_party_for_cookies); |
| 118 |
| 119 ResumeIfDeferred(); |
| 120 } |
| 121 |
| 122 void AsyncResourceHandler::OnDataReceivedACK() { |
| 123 // If the pending data count was higher than the max, resume the request. |
| 124 if (--pending_data_count_ == kMaxPendingDataMessages) { |
| 125 // Decrement the pending data count one more time because we also |
| 126 // incremented it before deferring the request. |
| 127 --pending_data_count_; |
| 128 |
| 129 // Resume the request. |
| 130 ResumeIfDeferred(); |
| 131 } |
| 94 } | 132 } |
| 95 | 133 |
| 96 bool AsyncResourceHandler::OnUploadProgress(int request_id, | 134 bool AsyncResourceHandler::OnUploadProgress(int request_id, |
| 97 uint64 position, | 135 uint64 position, |
| 98 uint64 size) { | 136 uint64 size) { |
| 99 return filter_->Send(new ResourceMsg_UploadProgress(routing_id_, request_id, | 137 return filter_->Send(new ResourceMsg_UploadProgress(routing_id_, request_id, |
| 100 position, size)); | 138 position, size)); |
| 101 } | 139 } |
| 102 | 140 |
| 103 bool AsyncResourceHandler::OnRequestRedirected(int request_id, | 141 bool AsyncResourceHandler::OnRequestRedirected(int request_id, |
| 104 const GURL& new_url, | 142 const GURL& new_url, |
| 105 ResourceResponse* response, | 143 ResourceResponse* response, |
| 106 bool* defer) { | 144 bool* defer) { |
| 107 *defer = true; | 145 *defer = did_defer_ = true; |
| 108 net::URLRequest* request = rdh_->GetURLRequest( | 146 |
| 109 GlobalRequestID(filter_->child_id(), request_id)); | |
| 110 if (rdh_->delegate()) | 147 if (rdh_->delegate()) |
| 111 rdh_->delegate()->OnRequestRedirected(request, response); | 148 rdh_->delegate()->OnRequestRedirected(request_, response); |
| 112 | 149 |
| 113 DevToolsNetLogObserver::PopulateResponseInfo(request, response); | 150 DevToolsNetLogObserver::PopulateResponseInfo(request_, response); |
| 114 response->request_start = request->creation_time(); | 151 response->request_start = request_->creation_time(); |
| 115 response->response_start = TimeTicks::Now(); | 152 response->response_start = TimeTicks::Now(); |
| 116 return filter_->Send(new ResourceMsg_ReceivedRedirect( | 153 return filter_->Send(new ResourceMsg_ReceivedRedirect( |
| 117 routing_id_, request_id, new_url, *response)); | 154 routing_id_, request_id, new_url, *response)); |
| 118 } | 155 } |
| 119 | 156 |
| 120 bool AsyncResourceHandler::OnResponseStarted(int request_id, | 157 bool AsyncResourceHandler::OnResponseStarted(int request_id, |
| 121 ResourceResponse* response, | 158 ResourceResponse* response, |
| 122 bool* defer) { | 159 bool* defer) { |
| 123 // For changes to the main frame, inform the renderer of the new URL's | 160 // For changes to the main frame, inform the renderer of the new URL's |
| 124 // per-host settings before the request actually commits. This way the | 161 // per-host settings before the request actually commits. This way the |
| 125 // renderer will be able to set these precisely at the time the | 162 // renderer will be able to set these precisely at the time the |
| 126 // request commits, avoiding the possibility of e.g. zooming the old content | 163 // request commits, avoiding the possibility of e.g. zooming the old content |
| 127 // or of having to layout the new content twice. | 164 // or of having to layout the new content twice. |
| 128 net::URLRequest* request = rdh_->GetURLRequest( | |
| 129 GlobalRequestID(filter_->child_id(), request_id)); | |
| 130 | 165 |
| 131 if (rdh_->delegate()) | 166 if (rdh_->delegate()) |
| 132 rdh_->delegate()->OnResponseStarted(request, response, filter_); | 167 rdh_->delegate()->OnResponseStarted(request_, response, filter_); |
| 133 | 168 |
| 134 DevToolsNetLogObserver::PopulateResponseInfo(request, response); | 169 DevToolsNetLogObserver::PopulateResponseInfo(request_, response); |
| 135 | 170 |
| 136 ResourceContext* resource_context = filter_->resource_context(); | 171 ResourceContext* resource_context = filter_->resource_context(); |
| 137 HostZoomMap* host_zoom_map = | 172 HostZoomMap* host_zoom_map = |
| 138 GetHostZoomMapForResourceContext(resource_context); | 173 GetHostZoomMapForResourceContext(resource_context); |
| 139 | 174 |
| 140 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request); | 175 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_); |
| 141 if (info->GetResourceType() == ResourceType::MAIN_FRAME && host_zoom_map) { | 176 if (info->GetResourceType() == ResourceType::MAIN_FRAME && host_zoom_map) { |
| 142 GURL request_url(request->url()); | 177 const GURL& request_url = request_->url(); |
| 143 filter_->Send(new ViewMsg_SetZoomLevelForLoadingURL( | 178 filter_->Send(new ViewMsg_SetZoomLevelForLoadingURL( |
| 144 info->GetRouteID(), | 179 info->GetRouteID(), |
| 145 request_url, host_zoom_map->GetZoomLevel(net::GetHostOrSpecFromURL( | 180 request_url, host_zoom_map->GetZoomLevel(net::GetHostOrSpecFromURL( |
| 146 request_url)))); | 181 request_url)))); |
| 147 } | 182 } |
| 148 | 183 |
| 149 response->request_start = request->creation_time(); | 184 response->request_start = request_->creation_time(); |
| 150 response->response_start = TimeTicks::Now(); | 185 response->response_start = TimeTicks::Now(); |
| 151 filter_->Send(new ResourceMsg_ReceivedResponse( | 186 filter_->Send(new ResourceMsg_ReceivedResponse( |
| 152 routing_id_, request_id, *response)); | 187 routing_id_, request_id, *response)); |
| 153 | 188 |
| 154 if (request->response_info().metadata) { | 189 if (request_->response_info().metadata) { |
| 155 std::vector<char> copy(request->response_info().metadata->data(), | 190 std::vector<char> copy(request_->response_info().metadata->data(), |
| 156 request->response_info().metadata->data() + | 191 request_->response_info().metadata->data() + |
| 157 request->response_info().metadata->size()); | 192 request_->response_info().metadata->size()); |
| 158 filter_->Send(new ResourceMsg_ReceivedCachedMetadata( | 193 filter_->Send(new ResourceMsg_ReceivedCachedMetadata( |
| 159 routing_id_, request_id, copy)); | 194 routing_id_, request_id, copy)); |
| 160 } | 195 } |
| 161 | 196 |
| 162 return true; | 197 return true; |
| 163 } | 198 } |
| 164 | 199 |
| 165 bool AsyncResourceHandler::OnWillStart(int request_id, | 200 bool AsyncResourceHandler::OnWillStart(int request_id, |
| 166 const GURL& url, | 201 const GURL& url, |
| 167 bool* defer) { | 202 bool* defer) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 return true; | 235 return true; |
| 201 DCHECK(read_buffer_.get()); | 236 DCHECK(read_buffer_.get()); |
| 202 | 237 |
| 203 if (read_buffer_->buffer_size() == *bytes_read) { | 238 if (read_buffer_->buffer_size() == *bytes_read) { |
| 204 // The network layer has saturated our buffer. Next time, we should give it | 239 // The network layer has saturated our buffer. Next time, we should give it |
| 205 // a bigger buffer for it to fill, to minimize the number of round trips we | 240 // a bigger buffer for it to fill, to minimize the number of round trips we |
| 206 // do with the renderer process. | 241 // do with the renderer process. |
| 207 next_buffer_size_ = std::min(next_buffer_size_ * 2, kMaxReadBufSize); | 242 next_buffer_size_ = std::min(next_buffer_size_ * 2, kMaxReadBufSize); |
| 208 } | 243 } |
| 209 | 244 |
| 210 if (!rdh_->WillSendData(filter_->child_id(), request_id, defer)) { | 245 if (!WillSendData(defer)) { |
| 211 // We should not send this data now, we have too many pending requests. | 246 // We should not send this data now, we have too many pending requests. |
| 212 return true; | 247 return true; |
| 213 } | 248 } |
| 214 | 249 |
| 215 base::SharedMemoryHandle handle; | 250 base::SharedMemoryHandle handle; |
| 216 if (!read_buffer_->shared_memory()->GiveToProcess( | 251 if (!read_buffer_->shared_memory()->GiveToProcess( |
| 217 filter_->peer_handle(), &handle)) { | 252 filter_->peer_handle(), &handle)) { |
| 218 // We wrongfully incremented the pending data count. Fake an ACK message | 253 // We wrongfully incremented the pending data count. Fake an ACK message |
| 219 // to fix this. We can't move this call above the WillSendData because | 254 // to fix this. We can't move this call above the WillSendData because |
| 220 // it's killing our read_buffer_, and we don't want that when we pause | 255 // it's killing our read_buffer_, and we don't want that when we pause |
| 221 // the request. | 256 // the request. |
| 222 rdh_->DataReceivedACK(filter_->child_id(), request_id); | 257 OnDataReceivedACK(); |
| 258 |
| 223 // We just unmapped the memory. | 259 // We just unmapped the memory. |
| 224 read_buffer_ = NULL; | 260 read_buffer_ = NULL; |
| 225 return false; | 261 return false; |
| 226 } | 262 } |
| 227 // We just unmapped the memory. | 263 // We just unmapped the memory. |
| 228 read_buffer_ = NULL; | 264 read_buffer_ = NULL; |
| 229 | 265 |
| 230 net::URLRequest* request = rdh_->GetURLRequest( | |
| 231 GlobalRequestID(filter_->child_id(), request_id)); | |
| 232 int encoded_data_length = | 266 int encoded_data_length = |
| 233 DevToolsNetLogObserver::GetAndResetEncodedDataLength(request); | 267 DevToolsNetLogObserver::GetAndResetEncodedDataLength(request_); |
| 234 filter_->Send(new ResourceMsg_DataReceived( | 268 filter_->Send(new ResourceMsg_DataReceived( |
| 235 routing_id_, request_id, handle, *bytes_read, encoded_data_length)); | 269 routing_id_, request_id, handle, *bytes_read, encoded_data_length)); |
| 236 | 270 |
| 237 return true; | 271 return true; |
| 238 } | 272 } |
| 239 | 273 |
| 240 void AsyncResourceHandler::OnDataDownloaded( | 274 void AsyncResourceHandler::OnDataDownloaded( |
| 241 int request_id, int bytes_downloaded) { | 275 int request_id, int bytes_downloaded) { |
| 242 filter_->Send(new ResourceMsg_DataDownloaded( | 276 filter_->Send(new ResourceMsg_DataDownloaded( |
| 243 routing_id_, request_id, bytes_downloaded)); | 277 routing_id_, request_id, bytes_downloaded)); |
| 244 } | 278 } |
| 245 | 279 |
| 246 bool AsyncResourceHandler::OnResponseCompleted( | 280 bool AsyncResourceHandler::OnResponseCompleted( |
| 247 int request_id, | 281 int request_id, |
| 248 const net::URLRequestStatus& status, | 282 const net::URLRequestStatus& status, |
| 249 const std::string& security_info) { | 283 const std::string& security_info) { |
| 250 // If we crash here, figure out what URL the renderer was requesting. | 284 // If we crash here, figure out what URL the renderer was requesting. |
| 251 // http://crbug.com/107692 | 285 // http://crbug.com/107692 |
| 252 char url_buf[128]; | 286 char url_buf[128]; |
| 253 base::strlcpy(url_buf, url_.spec().c_str(), arraysize(url_buf)); | 287 base::strlcpy(url_buf, request_->url().spec().c_str(), arraysize(url_buf)); |
| 254 base::debug::Alias(url_buf); | 288 base::debug::Alias(url_buf); |
| 255 | 289 |
| 256 TimeTicks completion_time = TimeTicks::Now(); | 290 TimeTicks completion_time = TimeTicks::Now(); |
| 257 filter_->Send(new ResourceMsg_RequestComplete(routing_id_, | 291 filter_->Send(new ResourceMsg_RequestComplete(routing_id_, |
| 258 request_id, | 292 request_id, |
| 259 status, | 293 status, |
| 260 security_info, | 294 security_info, |
| 261 completion_time)); | 295 completion_time)); |
| 262 | 296 |
| 263 // If we still have a read buffer, then see about caching it for later... | 297 // If we still have a read buffer, then see about caching it for later... |
| (...skipping 12 matching lines...) Expand all Loading... |
| 276 // static | 310 // static |
| 277 void AsyncResourceHandler::GlobalCleanup() { | 311 void AsyncResourceHandler::GlobalCleanup() { |
| 278 if (g_spare_read_buffer) { | 312 if (g_spare_read_buffer) { |
| 279 // Avoid the CHECK in SharedIOBuffer::~SharedIOBuffer(). | 313 // Avoid the CHECK in SharedIOBuffer::~SharedIOBuffer(). |
| 280 SharedIOBuffer* tmp = g_spare_read_buffer; | 314 SharedIOBuffer* tmp = g_spare_read_buffer; |
| 281 g_spare_read_buffer = NULL; | 315 g_spare_read_buffer = NULL; |
| 282 tmp->Release(); | 316 tmp->Release(); |
| 283 } | 317 } |
| 284 } | 318 } |
| 285 | 319 |
| 320 bool AsyncResourceHandler::WillSendData(bool* defer) { |
| 321 if (++pending_data_count_ > kMaxPendingDataMessages) { |
| 322 // We reached the max number of data messages that can be sent to |
| 323 // the renderer for a given request. Pause the request and wait for |
| 324 // the renderer to start processing them before resuming it. |
| 325 *defer = did_defer_ = true; |
| 326 return false; |
| 327 } |
| 328 |
| 329 return true; |
| 330 } |
| 331 |
| 332 void AsyncResourceHandler::ResumeIfDeferred() { |
| 333 if (did_defer_) { |
| 334 did_defer_ = false; |
| 335 controller()->Resume(); |
| 336 } |
| 337 } |
| 338 |
| 286 } // namespace content | 339 } // namespace content |
| OLD | NEW |