Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Side by Side Diff: content/browser/renderer_host/async_resource_handler.cc

Issue 11414299: Add content/browser/loader/ for resource loading related classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "content/browser/renderer_host/async_resource_handler.h"
6
7 #include <algorithm>
8 #include <vector>
9
10 #include "base/command_line.h"
11 #include "base/debug/alias.h"
12 #include "base/hash_tables.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/shared_memory.h"
16 #include "base/string_number_conversions.h"
17 #include "content/browser/debugger/devtools_netlog_observer.h"
18 #include "content/browser/host_zoom_map_impl.h"
19 #include "content/browser/renderer_host/resource_buffer.h"
20 #include "content/browser/renderer_host/resource_dispatcher_host_impl.h"
21 #include "content/browser/renderer_host/resource_message_filter.h"
22 #include "content/browser/renderer_host/resource_request_info_impl.h"
23 #include "content/browser/resource_context_impl.h"
24 #include "content/common/resource_messages.h"
25 #include "content/common/view_messages.h"
26 #include "content/public/browser/global_request_id.h"
27 #include "content/public/browser/resource_dispatcher_host_delegate.h"
28 #include "content/public/common/resource_response.h"
29 #include "net/base/io_buffer.h"
30 #include "net/base/load_flags.h"
31 #include "net/base/net_log.h"
32 #include "net/base/net_util.h"
33 #include "webkit/glue/resource_loader_bridge.h"
34
35 using base::TimeTicks;
36
37 namespace content {
38 namespace {
39
40 static int kBufferSize = 1024 * 512;
41 static int kMinAllocationSize = 1024 * 4;
42 static int kMaxAllocationSize = 1024 * 32;
43
44 void GetNumericArg(const std::string& name, int* result) {
45 const std::string& value =
46 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name);
47 if (!value.empty())
48 base::StringToInt(value, result);
49 }
50
51 void InitializeResourceBufferConstants() {
52 static bool did_init = false;
53 if (did_init)
54 return;
55 did_init = true;
56
57 GetNumericArg("resource-buffer-size", &kBufferSize);
58 GetNumericArg("resource-buffer-min-allocation-size", &kMinAllocationSize);
59 GetNumericArg("resource-buffer-max-allocation-size", &kMaxAllocationSize);
60 }
61
62 int CalcUsedPercentage(int bytes_read, int buffer_size) {
63 double ratio = static_cast<double>(bytes_read) / buffer_size;
64 return static_cast<int>(ratio * 100.0 + 0.5); // Round to nearest integer.
65 }
66
67 } // namespace
68
69 class DependentIOBuffer : public net::WrappedIOBuffer {
70 public:
71 DependentIOBuffer(ResourceBuffer* backing, char* memory)
72 : net::WrappedIOBuffer(memory),
73 backing_(backing) {
74 }
75 private:
76 ~DependentIOBuffer() {}
77 scoped_refptr<ResourceBuffer> backing_;
78 };
79
80 AsyncResourceHandler::AsyncResourceHandler(
81 ResourceMessageFilter* filter,
82 int routing_id,
83 net::URLRequest* request,
84 ResourceDispatcherHostImpl* rdh)
85 : filter_(filter),
86 routing_id_(routing_id),
87 request_(request),
88 rdh_(rdh),
89 pending_data_count_(0),
90 allocation_size_(0),
91 did_defer_(false),
92 sent_received_response_msg_(false),
93 sent_first_data_msg_(false) {
94 // Set a back-pointer from ResourceRequestInfoImpl to |this|, so that the
95 // ResourceDispatcherHostImpl can send us IPC messages.
96 // TODO(darin): Implement an IPC message filter instead?
97 ResourceRequestInfoImpl::ForRequest(request_)->set_async_handler(this);
98
99 InitializeResourceBufferConstants();
100 }
101
102 AsyncResourceHandler::~AsyncResourceHandler() {
103 // Cleanup back-pointer stored on the request info.
104 ResourceRequestInfoImpl::ForRequest(request_)->set_async_handler(NULL);
105 }
106
107 void AsyncResourceHandler::OnFollowRedirect(
108 bool has_new_first_party_for_cookies,
109 const GURL& new_first_party_for_cookies) {
110 if (!request_->status().is_success()) {
111 DVLOG(1) << "OnFollowRedirect for invalid request";
112 return;
113 }
114
115 if (has_new_first_party_for_cookies)
116 request_->set_first_party_for_cookies(new_first_party_for_cookies);
117
118 ResumeIfDeferred();
119 }
120
121 void AsyncResourceHandler::OnDataReceivedACK() {
122 --pending_data_count_;
123
124 buffer_->RecycleLeastRecentlyAllocated();
125 if (buffer_->CanAllocate())
126 ResumeIfDeferred();
127 }
128
129 bool AsyncResourceHandler::OnUploadProgress(int request_id,
130 uint64 position,
131 uint64 size) {
132 return filter_->Send(new ResourceMsg_UploadProgress(routing_id_, request_id,
133 position, size));
134 }
135
136 bool AsyncResourceHandler::OnRequestRedirected(int request_id,
137 const GURL& new_url,
138 ResourceResponse* response,
139 bool* defer) {
140 *defer = did_defer_ = true;
141
142 if (rdh_->delegate()) {
143 rdh_->delegate()->OnRequestRedirected(new_url, request_,
144 filter_->resource_context(),
145 response);
146 }
147
148 DevToolsNetLogObserver::PopulateResponseInfo(request_, response);
149 response->head.request_start = request_->creation_time();
150 response->head.response_start = TimeTicks::Now();
151 return filter_->Send(new ResourceMsg_ReceivedRedirect(
152 routing_id_, request_id, new_url, response->head));
153 }
154
155 bool AsyncResourceHandler::OnResponseStarted(int request_id,
156 ResourceResponse* response,
157 bool* defer) {
158 // For changes to the main frame, inform the renderer of the new URL's
159 // per-host settings before the request actually commits. This way the
160 // renderer will be able to set these precisely at the time the
161 // request commits, avoiding the possibility of e.g. zooming the old content
162 // or of having to layout the new content twice.
163
164 ResourceContext* resource_context = filter_->resource_context();
165 if (rdh_->delegate()) {
166 rdh_->delegate()->OnResponseStarted(request_, resource_context, response,
167 filter_);
168 }
169
170 DevToolsNetLogObserver::PopulateResponseInfo(request_, response);
171
172 HostZoomMap* host_zoom_map =
173 GetHostZoomMapForResourceContext(resource_context);
174
175 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request_);
176 if (info->GetResourceType() == ResourceType::MAIN_FRAME && host_zoom_map) {
177 const GURL& request_url = request_->url();
178 filter_->Send(new ViewMsg_SetZoomLevelForLoadingURL(
179 info->GetRouteID(),
180 request_url, host_zoom_map->GetZoomLevel(net::GetHostOrSpecFromURL(
181 request_url))));
182 }
183
184 response->head.request_start = request_->creation_time();
185 response->head.response_start = TimeTicks::Now();
186 filter_->Send(new ResourceMsg_ReceivedResponse(
187 routing_id_, request_id, response->head));
188 sent_received_response_msg_ = true;
189
190 if (request_->response_info().metadata) {
191 std::vector<char> copy(request_->response_info().metadata->data(),
192 request_->response_info().metadata->data() +
193 request_->response_info().metadata->size());
194 filter_->Send(new ResourceMsg_ReceivedCachedMetadata(
195 routing_id_, request_id, copy));
196 }
197
198 return true;
199 }
200
201 bool AsyncResourceHandler::OnWillStart(int request_id,
202 const GURL& url,
203 bool* defer) {
204 return true;
205 }
206
207 bool AsyncResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
208 int* buf_size, int min_size) {
209 DCHECK_EQ(-1, min_size);
210
211 if (!EnsureResourceBufferIsInitialized())
212 return false;
213
214 DCHECK(buffer_->CanAllocate());
215 char* memory = buffer_->Allocate(&allocation_size_);
216 CHECK(memory);
217
218 *buf = new DependentIOBuffer(buffer_, memory);
219 *buf_size = allocation_size_;
220
221 UMA_HISTOGRAM_CUSTOM_COUNTS(
222 "Net.AsyncResourceHandler_SharedIOBuffer_Alloc",
223 *buf_size, 0, kMaxAllocationSize, 100);
224 return true;
225 }
226
227 bool AsyncResourceHandler::OnReadCompleted(int request_id, int bytes_read,
228 bool* defer) {
229 if (!bytes_read)
230 return true;
231
232 buffer_->ShrinkLastAllocation(bytes_read);
233
234 UMA_HISTOGRAM_CUSTOM_COUNTS(
235 "Net.AsyncResourceHandler_SharedIOBuffer_Used",
236 bytes_read, 0, kMaxAllocationSize, 100);
237 UMA_HISTOGRAM_PERCENTAGE(
238 "Net.AsyncResourceHandler_SharedIOBuffer_UsedPercentage",
239 CalcUsedPercentage(bytes_read, allocation_size_));
240
241 if (!sent_first_data_msg_) {
242 base::SharedMemoryHandle handle;
243 int size;
244 if (!buffer_->ShareToProcess(filter_->peer_handle(), &handle, &size))
245 return false;
246 filter_->Send(
247 new ResourceMsg_SetDataBuffer(routing_id_, request_id, handle, size));
248 sent_first_data_msg_ = true;
249 }
250
251 int data_offset = buffer_->GetLastAllocationOffset();
252 int encoded_data_length =
253 DevToolsNetLogObserver::GetAndResetEncodedDataLength(request_);
254
255 filter_->Send(
256 new ResourceMsg_DataReceived(routing_id_, request_id, data_offset,
257 bytes_read, encoded_data_length));
258 ++pending_data_count_;
259 UMA_HISTOGRAM_CUSTOM_COUNTS(
260 "Net.AsyncResourceHandler_PendingDataCount",
261 pending_data_count_, 0, 100, 100);
262
263 if (!buffer_->CanAllocate()) {
264 UMA_HISTOGRAM_CUSTOM_COUNTS(
265 "Net.AsyncResourceHandler_PendingDataCount_WhenFull",
266 pending_data_count_, 0, 100, 100);
267 *defer = did_defer_ = true;
268 }
269
270 return true;
271 }
272
273 void AsyncResourceHandler::OnDataDownloaded(
274 int request_id, int bytes_downloaded) {
275 filter_->Send(new ResourceMsg_DataDownloaded(
276 routing_id_, request_id, bytes_downloaded));
277 }
278
279 bool AsyncResourceHandler::OnResponseCompleted(
280 int request_id,
281 const net::URLRequestStatus& status,
282 const std::string& security_info) {
283 // If we crash here, figure out what URL the renderer was requesting.
284 // http://crbug.com/107692
285 char url_buf[128];
286 base::strlcpy(url_buf, request_->url().spec().c_str(), arraysize(url_buf));
287 base::debug::Alias(url_buf);
288
289 // TODO(gavinp): Remove this CHECK when we figure out the cause of
290 // http://crbug.com/124680 . This check mirrors closely check in
291 // WebURLLoaderImpl::OnCompletedRequest that routes this message to a WebCore
292 // ResourceHandleInternal which asserts on its state and crashes. By crashing
293 // when the message is sent, we should get better crash reports.
294 CHECK(status.status() != net::URLRequestStatus::SUCCESS ||
295 sent_received_response_msg_);
296
297 TimeTicks completion_time = TimeTicks::Now();
298
299 int error_code = status.error();
300 bool was_ignored_by_handler =
301 ResourceRequestInfoImpl::ForRequest(request_)->WasIgnoredByHandler();
302
303 DCHECK(status.status() != net::URLRequestStatus::IO_PENDING);
304 // If this check fails, then we're in an inconsistent state because all
305 // requests ignored by the handler should be canceled (which should result in
306 // the ERR_ABORTED error code).
307 DCHECK(!was_ignored_by_handler || error_code == net::ERR_ABORTED);
308
309 // TODO(mkosiba): Fix up cases where we create a URLRequestStatus
310 // with a status() != SUCCESS and an error_code() == net::OK.
311 if (status.status() == net::URLRequestStatus::CANCELED &&
312 error_code == net::OK) {
313 error_code = net::ERR_ABORTED;
314 } else if (status.status() == net::URLRequestStatus::FAILED &&
315 error_code == net::OK) {
316 error_code = net::ERR_FAILED;
317 }
318
319 filter_->Send(new ResourceMsg_RequestComplete(routing_id_,
320 request_id,
321 error_code,
322 was_ignored_by_handler,
323 security_info,
324 completion_time));
325 return true;
326 }
327
328 bool AsyncResourceHandler::EnsureResourceBufferIsInitialized() {
329 if (buffer_ && buffer_->IsInitialized())
330 return true;
331
332 buffer_ = new ResourceBuffer();
333 return buffer_->Initialize(kBufferSize,
334 kMinAllocationSize,
335 kMaxAllocationSize);
336 }
337
338 void AsyncResourceHandler::ResumeIfDeferred() {
339 if (did_defer_) {
340 did_defer_ = false;
341 controller()->Resume();
342 }
343 }
344
345 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/async_resource_handler.h ('k') | content/browser/renderer_host/buffered_resource_handler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698