OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "chrome/browser/renderer_host/async_resource_handler.h" | 5 #include "chrome/browser/renderer_host/async_resource_handler.h" |
6 | 6 |
| 7 #include "base/hash_tables.h" |
7 #include "base/logging.h" | 8 #include "base/logging.h" |
8 #include "base/process.h" | 9 #include "base/process.h" |
9 #include "base/shared_memory.h" | 10 #include "base/shared_memory.h" |
10 #include "chrome/browser/browser_process.h" | 11 #include "chrome/browser/browser_process.h" |
11 #include "chrome/browser/net/chrome_net_log.h" | 12 #include "chrome/browser/net/chrome_net_log.h" |
12 #include "chrome/browser/net/chrome_url_request_context.h" | 13 #include "chrome/browser/net/chrome_url_request_context.h" |
13 #include "chrome/browser/net/passive_log_collector.h" | 14 #include "chrome/browser/net/load_timing_observer.h" |
14 #include "chrome/browser/renderer_host/global_request_id.h" | 15 #include "chrome/browser/renderer_host/global_request_id.h" |
15 #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" | 16 #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h" |
16 #include "chrome/common/render_messages.h" | 17 #include "chrome/common/render_messages.h" |
17 #include "net/base/io_buffer.h" | 18 #include "net/base/io_buffer.h" |
18 #include "net/base/load_flags.h" | 19 #include "net/base/load_flags.h" |
19 #include "net/base/net_log.h" | 20 #include "net/base/net_log.h" |
20 #include "webkit/glue/resource_loader_bridge.h" | 21 #include "webkit/glue/resource_loader_bridge.h" |
21 | 22 |
22 using base::Time; | 23 using base::Time; |
23 using base::TimeTicks; | 24 using base::TimeTicks; |
24 | 25 |
25 namespace { | 26 namespace { |
26 | 27 |
27 // When reading, we don't know if we are going to get EOF (0 bytes read), so | 28 // When reading, we don't know if we are going to get EOF (0 bytes read), so |
28 // we typically have a buffer that we allocated but did not use. We keep | 29 // we typically have a buffer that we allocated but did not use. We keep |
29 // this buffer around for the next read as a small optimization. | 30 // this buffer around for the next read as a small optimization. |
30 SharedIOBuffer* g_spare_read_buffer = NULL; | 31 SharedIOBuffer* g_spare_read_buffer = NULL; |
31 | 32 |
32 // The initial size of the shared memory buffer. (32 kilobytes). | 33 // The initial size of the shared memory buffer. (32 kilobytes). |
33 const int kInitialReadBufSize = 32768; | 34 const int kInitialReadBufSize = 32768; |
34 | 35 |
35 // The maximum size of the shared memory buffer. (512 kilobytes). | 36 // The maximum size of the shared memory buffer. (512 kilobytes). |
36 const int kMaxReadBufSize = 524288; | 37 const int kMaxReadBufSize = 524288; |
37 | 38 |
38 // We know that this conversion is not solid and suffers from world clock | |
39 // changes, but it should be good enough for the load timing info. | |
40 static Time TimeTicksToTime(const TimeTicks& time_ticks) { | |
41 static int64 tick_to_time_offset; | |
42 static bool tick_to_time_offset_available = false; | |
43 if (!tick_to_time_offset_available) { | |
44 int64 cur_time = (Time::Now() - Time()).InMicroseconds(); | |
45 int64 cur_time_ticks = (TimeTicks::Now() - TimeTicks()).InMicroseconds(); | |
46 // If we add this number to a time tick value, it gives the timestamp. | |
47 tick_to_time_offset = cur_time - cur_time_ticks; | |
48 tick_to_time_offset_available = true; | |
49 } | |
50 return Time::FromInternalValue(time_ticks.ToInternalValue() + | |
51 tick_to_time_offset); | |
52 } | |
53 | |
54 } // namespace | 39 } // namespace |
55 | 40 |
56 // Our version of IOBuffer that uses shared memory. | 41 // Our version of IOBuffer that uses shared memory. |
57 class SharedIOBuffer : public net::IOBuffer { | 42 class SharedIOBuffer : public net::IOBuffer { |
58 public: | 43 public: |
59 explicit SharedIOBuffer(int buffer_size) | 44 explicit SharedIOBuffer(int buffer_size) |
60 : net::IOBuffer(), | 45 : net::IOBuffer(), |
61 ok_(false), | 46 ok_(false), |
62 buffer_size_(buffer_size) {} | 47 buffer_size_(buffer_size) {} |
63 | 48 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 process_handle_(process_handle), | 86 process_handle_(process_handle), |
102 rdh_(resource_dispatcher_host), | 87 rdh_(resource_dispatcher_host), |
103 next_buffer_size_(kInitialReadBufSize) { | 88 next_buffer_size_(kInitialReadBufSize) { |
104 } | 89 } |
105 | 90 |
106 AsyncResourceHandler::~AsyncResourceHandler() { | 91 AsyncResourceHandler::~AsyncResourceHandler() { |
107 } | 92 } |
108 | 93 |
109 void AsyncResourceHandler::PopulateTimingInfo(URLRequest* request, | 94 void AsyncResourceHandler::PopulateTimingInfo(URLRequest* request, |
110 ResourceResponse* response) { | 95 ResourceResponse* response) { |
111 uint32 source_id = request->net_log().source().id; | 96 if (!(request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING)) |
| 97 return; |
| 98 |
112 ChromeNetLog* chrome_net_log = static_cast<ChromeNetLog*>( | 99 ChromeNetLog* chrome_net_log = static_cast<ChromeNetLog*>( |
113 request->net_log().net_log()); | 100 request->net_log().net_log()); |
114 | 101 if (chrome_net_log == NULL) |
115 PassiveLogCollector* collector = chrome_net_log->passive_collector(); | |
116 PassiveLogCollector::SourceTracker* url_tracker = | |
117 static_cast<PassiveLogCollector::SourceTracker*>(collector-> | |
118 GetTrackerForSourceType(net::NetLog::SOURCE_URL_REQUEST)); | |
119 | |
120 PassiveLogCollector::SourceInfo* url_request = | |
121 url_tracker->GetSourceInfo(source_id); | |
122 | |
123 if (!url_request) | |
124 return; | 102 return; |
125 | 103 |
126 ResourceResponseHead& response_head = response->response_head; | 104 uint32 source_id = request->net_log().source().id; |
127 webkit_glue::ResourceLoaderBridge::LoadTimingInfo& timing = | 105 LoadTimingObserver* observer = chrome_net_log->load_timing_observer(); |
128 response_head.load_timing; | 106 LoadTimingObserver::URLRequestRecord* record = |
129 | 107 observer->GetURLRequestRecord(source_id); |
130 uint32 connect_job_id = net::NetLog::Source::kInvalidId; | 108 if (record) { |
131 | 109 response->response_head.connection_id = record->socket_log_id; |
132 base::TimeTicks base_time; | 110 response->response_head.connection_reused = record->socket_reused; |
133 | 111 response->response_head.load_timing = record->timing; |
134 for (PassiveLogCollector::EntryList::const_iterator it = | |
135 url_request->entries.begin(); | |
136 it != url_request->entries.end(); ++it) { | |
137 const PassiveLogCollector::Entry& entry = *it; | |
138 | |
139 bool is_begin = entry.phase == net::NetLog::PHASE_BEGIN; | |
140 bool is_end = entry.phase == net::NetLog::PHASE_END; | |
141 | |
142 switch (entry.type) { | |
143 case net::NetLog::TYPE_URL_REQUEST_START_JOB: | |
144 if (is_begin) { | |
145 // Reset state so that we captured last redirect only. | |
146 timing.base_time = TimeTicksToTime(entry.time); | |
147 base_time = entry.time; | |
148 connect_job_id = net::NetLog::Source::kInvalidId; | |
149 } | |
150 break; | |
151 case net::NetLog::TYPE_PROXY_SERVICE: | |
152 if (is_begin) { | |
153 timing.proxy_start = static_cast<int32>( | |
154 (entry.time - base_time).InMillisecondsRoundedUp()); | |
155 } else if (is_end) { | |
156 timing.proxy_end = static_cast<int32>( | |
157 (entry.time - base_time).InMillisecondsRoundedUp()); | |
158 } | |
159 break; | |
160 case net::NetLog::TYPE_SOCKET_POOL: | |
161 if (is_begin) { | |
162 timing.connect_start = static_cast<int32>( | |
163 (entry.time - base_time).InMillisecondsRoundedUp()); | |
164 } else if (is_end && | |
165 connect_job_id != net::NetLog::Source::kInvalidId) { | |
166 timing.connect_end = static_cast<int32>( | |
167 (entry.time - base_time).InMillisecondsRoundedUp()); | |
168 } | |
169 break; | |
170 case net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB: | |
171 connect_job_id = static_cast<net::NetLogSourceParameter*>( | |
172 entry.params.get())->value().id; | |
173 break; | |
174 case net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET: | |
175 { | |
176 uint32 log_id = static_cast<net::NetLogSourceParameter*>( | |
177 entry.params.get())->value().id; | |
178 response->response_head.connection_id = | |
179 log_id != net::NetLog::Source::kInvalidId ? log_id : 0; | |
180 } | |
181 break; | |
182 case net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST: | |
183 case net::NetLog::TYPE_SPDY_TRANSACTION_SEND_REQUEST: | |
184 if (is_begin) { | |
185 timing.send_start = static_cast<int32>( | |
186 (entry.time - base_time).InMillisecondsRoundedUp()); | |
187 } else if (is_end) { | |
188 timing.send_end = static_cast<int32>( | |
189 (entry.time - base_time).InMillisecondsRoundedUp()); | |
190 } | |
191 break; | |
192 case net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS: | |
193 case net::NetLog::TYPE_SPDY_TRANSACTION_READ_HEADERS: | |
194 if (is_begin) { | |
195 timing.receive_headers_start = static_cast<int32>( | |
196 (entry.time - base_time).InMillisecondsRoundedUp()); | |
197 } else if (is_end) { | |
198 timing.receive_headers_end = static_cast<int32>( | |
199 (entry.time - base_time).InMillisecondsRoundedUp()); | |
200 } | |
201 break; | |
202 default: | |
203 break; | |
204 } | |
205 } | |
206 | |
207 // For DNS time, get the ID of the "connect job" from the | |
208 // BOUND_TO_CONNECT_JOB entry, in its source info look at the | |
209 // HOST_RESOLVER_IMPL times. | |
210 if (connect_job_id == net::NetLog::Source::kInvalidId) { | |
211 // Clean up connection time to match contract. | |
212 timing.connect_start = -1; | |
213 timing.connect_end = -1; | |
214 return; | |
215 } | |
216 | |
217 PassiveLogCollector::SourceTracker* connect_job_tracker = | |
218 static_cast<PassiveLogCollector::SourceTracker*>( | |
219 collector->GetTrackerForSourceType(net::NetLog::SOURCE_CONNECT_JOB)); | |
220 PassiveLogCollector::SourceInfo* connect_job = | |
221 connect_job_tracker->GetSourceInfo(connect_job_id); | |
222 if (!connect_job) | |
223 return; | |
224 | |
225 for (PassiveLogCollector::EntryList::const_iterator it = | |
226 connect_job->entries.begin(); | |
227 it != connect_job->entries.end(); ++it) { | |
228 const PassiveLogCollector::Entry& entry = *it; | |
229 if (entry.phase == net::NetLog::PHASE_BEGIN && | |
230 entry.type == net::NetLog::TYPE_HOST_RESOLVER_IMPL) { | |
231 timing.dns_start = static_cast<int32>( | |
232 (entry.time - base_time).InMillisecondsRoundedUp()); | |
233 } else if (entry.phase == net::NetLog::PHASE_END && | |
234 entry.type == net::NetLog::TYPE_HOST_RESOLVER_IMPL) { | |
235 timing.dns_end = static_cast<int32>( | |
236 (entry.time - base_time).InMillisecondsRoundedUp()); | |
237 // Connect time already includes dns time, subtract it here. | |
238 break; | |
239 } | |
240 } | 112 } |
241 } | 113 } |
242 | 114 |
243 bool AsyncResourceHandler::OnUploadProgress(int request_id, | 115 bool AsyncResourceHandler::OnUploadProgress(int request_id, |
244 uint64 position, | 116 uint64 position, |
245 uint64 size) { | 117 uint64 size) { |
246 return receiver_->Send(new ViewMsg_Resource_UploadProgress(routing_id_, | 118 return receiver_->Send(new ViewMsg_Resource_UploadProgress(routing_id_, |
247 request_id, | 119 request_id, |
248 position, size)); | 120 position, size)); |
249 } | 121 } |
250 | 122 |
251 bool AsyncResourceHandler::OnRequestRedirected(int request_id, | 123 bool AsyncResourceHandler::OnRequestRedirected(int request_id, |
252 const GURL& new_url, | 124 const GURL& new_url, |
253 ResourceResponse* response, | 125 ResourceResponse* response, |
254 bool* defer) { | 126 bool* defer) { |
255 *defer = true; | 127 *defer = true; |
256 URLRequest* request = rdh_->GetURLRequest( | 128 URLRequest* request = rdh_->GetURLRequest( |
257 GlobalRequestID(process_id_, request_id)); | 129 GlobalRequestID(process_id_, request_id)); |
258 // TODO(pfeldman): enable once migrated to LoadTimingObserver. | 130 PopulateTimingInfo(request, response); |
259 if (false && request && (request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING)
) | |
260 PopulateTimingInfo(request, response); | |
261 return receiver_->Send(new ViewMsg_Resource_ReceivedRedirect( | 131 return receiver_->Send(new ViewMsg_Resource_ReceivedRedirect( |
262 routing_id_, request_id, new_url, response->response_head)); | 132 routing_id_, request_id, new_url, response->response_head)); |
263 } | 133 } |
264 | 134 |
265 bool AsyncResourceHandler::OnResponseStarted(int request_id, | 135 bool AsyncResourceHandler::OnResponseStarted(int request_id, |
266 ResourceResponse* response) { | 136 ResourceResponse* response) { |
267 // For changes to the main frame, inform the renderer of the new URL's | 137 // For changes to the main frame, inform the renderer of the new URL's |
268 // per-host settings before the request actually commits. This way the | 138 // per-host settings before the request actually commits. This way the |
269 // renderer will be able to set these precisely at the time the | 139 // renderer will be able to set these precisely at the time the |
270 // request commits, avoiding the possibility of e.g. zooming the old content | 140 // request commits, avoiding the possibility of e.g. zooming the old content |
271 // or of having to layout the new content twice. | 141 // or of having to layout the new content twice. |
272 URLRequest* request = rdh_->GetURLRequest( | 142 URLRequest* request = rdh_->GetURLRequest( |
273 GlobalRequestID(process_id_, request_id)); | 143 GlobalRequestID(process_id_, request_id)); |
274 | 144 |
275 // TODO(pfeldman): enable once migrated to LoadTimingObserver. | 145 PopulateTimingInfo(request, response); |
276 if (false && request->load_flags() & net::LOAD_ENABLE_LOAD_TIMING) | |
277 PopulateTimingInfo(request, response); | |
278 | 146 |
279 ResourceDispatcherHostRequestInfo* info = rdh_->InfoForRequest(request); | 147 ResourceDispatcherHostRequestInfo* info = rdh_->InfoForRequest(request); |
280 if (info->resource_type() == ResourceType::MAIN_FRAME) { | 148 if (info->resource_type() == ResourceType::MAIN_FRAME) { |
281 GURL request_url(request->url()); | 149 GURL request_url(request->url()); |
282 ChromeURLRequestContext* context = | 150 ChromeURLRequestContext* context = |
283 static_cast<ChromeURLRequestContext*>(request->context()); | 151 static_cast<ChromeURLRequestContext*>(request->context()); |
284 if (context) { | 152 if (context) { |
285 receiver_->Send(new ViewMsg_SetContentSettingsForLoadingURL( | 153 receiver_->Send(new ViewMsg_SetContentSettingsForLoadingURL( |
286 info->route_id(), request_url, | 154 info->route_id(), request_url, |
287 context->host_content_settings_map()->GetContentSettings( | 155 context->host_content_settings_map()->GetContentSettings( |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 | 269 |
402 // static | 270 // static |
403 void AsyncResourceHandler::GlobalCleanup() { | 271 void AsyncResourceHandler::GlobalCleanup() { |
404 if (g_spare_read_buffer) { | 272 if (g_spare_read_buffer) { |
405 // Avoid the CHECK in SharedIOBuffer::~SharedIOBuffer(). | 273 // Avoid the CHECK in SharedIOBuffer::~SharedIOBuffer(). |
406 SharedIOBuffer* tmp = g_spare_read_buffer; | 274 SharedIOBuffer* tmp = g_spare_read_buffer; |
407 g_spare_read_buffer = NULL; | 275 g_spare_read_buffer = NULL; |
408 tmp->Release(); | 276 tmp->Release(); |
409 } | 277 } |
410 } | 278 } |
OLD | NEW |