OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "net/base/net_log_util.h" | |
6 | |
7 #include <algorithm> | |
8 #include <string> | |
9 #include <vector> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/logging.h" | |
13 #include "base/metrics/field_trial.h" | |
14 #include "base/strings/string_number_conversions.h" | |
15 #include "base/strings/string_split.h" | |
16 #include "base/strings/string_util.h" | |
17 #include "base/time/time.h" | |
18 #include "base/values.h" | |
19 #include "net/base/address_family.h" | |
20 #include "net/base/load_states.h" | |
21 #include "net/base/net_errors.h" | |
22 #include "net/base/net_log.h" | |
23 #include "net/base/sdch_manager.h" | |
24 #include "net/disk_cache/disk_cache.h" | |
25 #include "net/dns/host_cache.h" | |
26 #include "net/dns/host_resolver.h" | |
27 #include "net/http/http_cache.h" | |
28 #include "net/http/http_network_session.h" | |
29 #include "net/http/http_server_properties.h" | |
30 #include "net/http/http_transaction_factory.h" | |
31 #include "net/proxy/proxy_config.h" | |
32 #include "net/proxy/proxy_retry_info.h" | |
33 #include "net/proxy/proxy_service.h" | |
34 #include "net/quic/quic_protocol.h" | |
35 #include "net/quic/quic_utils.h" | |
36 #include "net/socket/ssl_client_socket.h" | |
37 #include "net/url_request/url_request.h" | |
38 #include "net/url_request/url_request_context.h" | |
39 | |
40 namespace net { | |
41 | |
42 namespace { | |
43 | |
44 // This should be incremented when significant changes are made that will | |
45 // invalidate the old loading code. | |
46 const int kLogFormatVersion = 1; | |
47 | |
48 struct StringToConstant { | |
49 const char* name; | |
50 const int constant; | |
51 }; | |
52 | |
53 const StringToConstant kCertStatusFlags[] = { | |
54 #define CERT_STATUS_FLAG(label, value) { #label, value }, | |
55 #include "net/cert/cert_status_flags_list.h" | |
56 #undef CERT_STATUS_FLAG | |
57 }; | |
58 | |
59 const StringToConstant kLoadFlags[] = { | |
60 #define LOAD_FLAG(label, value) { #label, value }, | |
61 #include "net/base/load_flags_list.h" | |
62 #undef LOAD_FLAG | |
63 }; | |
64 | |
65 const StringToConstant kLoadStateTable[] = { | |
66 #define LOAD_STATE(label) { # label, net::LOAD_STATE_ ## label }, | |
67 #include "net/base/load_states_list.h" | |
68 #undef LOAD_STATE | |
69 }; | |
70 | |
71 const short kNetErrors[] = { | |
72 #define NET_ERROR(label, value) value, | |
73 #include "net/base/net_error_list.h" | |
74 #undef NET_ERROR | |
75 }; | |
76 | |
77 const StringToConstant kSdchProblems[] = { | |
78 #define SDCH_PROBLEM_CODE(label, value) \ | |
79 { #label, value } \ | |
80 , | |
81 #include "net/base/sdch_problem_code_list.h" | |
82 #undef SDCH_PROBLEM_CODE | |
83 }; | |
84 | |
85 const char* NetInfoSourceToString(NetInfoSource source) { | |
86 switch (source) { | |
87 #define NET_INFO_SOURCE(label, string, value) \ | |
88 case NET_INFO_ ## label: \ | |
89 return string; | |
90 #include "net/base/net_info_source_list.h" | |
91 #undef NET_INFO_SOURCE | |
92 case NET_INFO_ALL_SOURCES: | |
93 return "All"; | |
94 } | |
95 return "?"; | |
96 } | |
97 | |
98 // Returns the disk cache backend for |context| if there is one, or NULL. | |
99 // Despite the name, can return an in memory "disk cache". | |
100 disk_cache::Backend* GetDiskCacheBackend(net::URLRequestContext* context) { | |
101 if (!context->http_transaction_factory()) | |
102 return NULL; | |
103 | |
104 net::HttpCache* http_cache = context->http_transaction_factory()->GetCache(); | |
105 if (!http_cache) | |
106 return NULL; | |
107 | |
108 return http_cache->GetCurrentBackend(); | |
109 } | |
110 | |
111 // Returns true if |request1| was created before |request2|. | |
112 bool RequestCreatedBefore(const net::URLRequest* request1, | |
113 const net::URLRequest* request2) { | |
114 if (request1->creation_time() < request2->creation_time()) | |
115 return true; | |
116 if (request1->creation_time() > request2->creation_time()) | |
117 return false; | |
118 // If requests were created at the same time, sort by ID. Mostly matters for | |
119 // testing purposes. | |
120 return request1->identifier() < request2->identifier(); | |
121 } | |
122 | |
123 // Returns a Value representing the state of a pre-existing URLRequest when | |
124 // net-internals was opened. | |
125 base::Value* GetRequestStateAsValue(const net::URLRequest* request, | |
126 net::NetLog::LogLevel log_level) { | |
127 return request->GetStateAsValue(); | |
128 } | |
129 | |
130 } // namespace | |
131 | |
132 scoped_ptr<base::DictionaryValue> GetNetConstants() { | |
133 scoped_ptr<base::DictionaryValue> constants_dict(new base::DictionaryValue()); | |
134 | |
135 // Version of the file format. | |
136 constants_dict->SetInteger("logFormatVersion", kLogFormatVersion); | |
137 | |
138 // Add a dictionary with information on the relationship between event type | |
139 // enums and their symbolic names. | |
140 constants_dict->Set("logEventTypes", net::NetLog::GetEventTypesAsValue()); | |
141 | |
142 // Add a dictionary with information about the relationship between CertStatus | |
143 // flags and their symbolic names. | |
144 { | |
145 base::DictionaryValue* dict = new base::DictionaryValue(); | |
146 | |
147 for (size_t i = 0; i < arraysize(kCertStatusFlags); i++) | |
148 dict->SetInteger(kCertStatusFlags[i].name, kCertStatusFlags[i].constant); | |
149 | |
150 constants_dict->Set("certStatusFlag", dict); | |
151 } | |
152 | |
153 // Add a dictionary with information about the relationship between load flag | |
154 // enums and their symbolic names. | |
155 { | |
156 base::DictionaryValue* dict = new base::DictionaryValue(); | |
157 | |
158 for (size_t i = 0; i < arraysize(kLoadFlags); i++) | |
159 dict->SetInteger(kLoadFlags[i].name, kLoadFlags[i].constant); | |
160 | |
161 constants_dict->Set("loadFlag", dict); | |
162 } | |
163 | |
164 // Add a dictionary with information about the relationship between load state | |
165 // enums and their symbolic names. | |
166 { | |
167 base::DictionaryValue* dict = new base::DictionaryValue(); | |
168 | |
169 for (size_t i = 0; i < arraysize(kLoadStateTable); i++) | |
170 dict->SetInteger(kLoadStateTable[i].name, kLoadStateTable[i].constant); | |
171 | |
172 constants_dict->Set("loadState", dict); | |
173 } | |
174 | |
175 { | |
176 base::DictionaryValue* dict = new base::DictionaryValue(); | |
177 #define NET_INFO_SOURCE(label, string, value) \ | |
178 dict->SetInteger(string, NET_INFO_ ## label); | |
179 #include "net/base/net_info_source_list.h" | |
180 #undef NET_INFO_SOURCE | |
181 constants_dict->Set("netInfoSources", dict); | |
182 } | |
183 | |
184 // Add information on the relationship between net error codes and their | |
185 // symbolic names. | |
186 { | |
187 base::DictionaryValue* dict = new base::DictionaryValue(); | |
188 | |
189 for (size_t i = 0; i < arraysize(kNetErrors); i++) | |
190 dict->SetInteger(ErrorToShortString(kNetErrors[i]), kNetErrors[i]); | |
191 | |
192 constants_dict->Set("netError", dict); | |
193 } | |
194 | |
195 // Add information on the relationship between QUIC error codes and their | |
196 // symbolic names. | |
197 { | |
198 base::DictionaryValue* dict = new base::DictionaryValue(); | |
199 | |
200 for (net::QuicErrorCode error = net::QUIC_NO_ERROR; | |
201 error < net::QUIC_LAST_ERROR; | |
202 error = static_cast<net::QuicErrorCode>(error + 1)) { | |
203 dict->SetInteger(net::QuicUtils::ErrorToString(error), | |
204 static_cast<int>(error)); | |
205 } | |
206 | |
207 constants_dict->Set("quicError", dict); | |
208 } | |
209 | |
210 // Add information on the relationship between QUIC RST_STREAM error codes | |
211 // and their symbolic names. | |
212 { | |
213 base::DictionaryValue* dict = new base::DictionaryValue(); | |
214 | |
215 for (net::QuicRstStreamErrorCode error = net::QUIC_STREAM_NO_ERROR; | |
216 error < net::QUIC_STREAM_LAST_ERROR; | |
217 error = static_cast<net::QuicRstStreamErrorCode>(error + 1)) { | |
218 dict->SetInteger(net::QuicUtils::StreamErrorToString(error), | |
219 static_cast<int>(error)); | |
220 } | |
221 | |
222 constants_dict->Set("quicRstStreamError", dict); | |
223 } | |
224 | |
225 // Add information on the relationship between SDCH problem codes and their | |
226 // symbolic names. | |
227 { | |
228 base::DictionaryValue* dict = new base::DictionaryValue(); | |
229 | |
230 for (size_t i = 0; i < arraysize(kSdchProblems); i++) | |
231 dict->SetInteger(kSdchProblems[i].name, kSdchProblems[i].constant); | |
232 | |
233 constants_dict->Set("sdchProblemCode", dict); | |
234 } | |
235 | |
236 // Information about the relationship between event phase enums and their | |
237 // symbolic names. | |
238 { | |
239 base::DictionaryValue* dict = new base::DictionaryValue(); | |
240 | |
241 dict->SetInteger("PHASE_BEGIN", net::NetLog::PHASE_BEGIN); | |
242 dict->SetInteger("PHASE_END", net::NetLog::PHASE_END); | |
243 dict->SetInteger("PHASE_NONE", net::NetLog::PHASE_NONE); | |
244 | |
245 constants_dict->Set("logEventPhase", dict); | |
246 } | |
247 | |
248 // Information about the relationship between source type enums and | |
249 // their symbolic names. | |
250 constants_dict->Set("logSourceType", net::NetLog::GetSourceTypesAsValue()); | |
251 | |
252 // Information about the relationship between LogLevel enums and their | |
253 // symbolic names. | |
254 { | |
255 base::DictionaryValue* dict = new base::DictionaryValue(); | |
256 | |
257 dict->SetInteger("LOG_ALL", net::NetLog::LOG_ALL); | |
258 dict->SetInteger("LOG_ALL_BUT_BYTES", net::NetLog::LOG_ALL_BUT_BYTES); | |
259 dict->SetInteger("LOG_STRIP_PRIVATE_DATA", | |
260 net::NetLog::LOG_STRIP_PRIVATE_DATA); | |
261 | |
262 constants_dict->Set("logLevelType", dict); | |
263 } | |
264 | |
265 // Information about the relationship between address family enums and | |
266 // their symbolic names. | |
267 { | |
268 base::DictionaryValue* dict = new base::DictionaryValue(); | |
269 | |
270 dict->SetInteger("ADDRESS_FAMILY_UNSPECIFIED", | |
271 net::ADDRESS_FAMILY_UNSPECIFIED); | |
272 dict->SetInteger("ADDRESS_FAMILY_IPV4", | |
273 net::ADDRESS_FAMILY_IPV4); | |
274 dict->SetInteger("ADDRESS_FAMILY_IPV6", | |
275 net::ADDRESS_FAMILY_IPV6); | |
276 | |
277 constants_dict->Set("addressFamily", dict); | |
278 } | |
279 | |
280 // Information about how the "time ticks" values we have given it relate to | |
281 // actual system times. (We used time ticks throughout since they are stable | |
282 // across system clock changes). | |
283 { | |
284 int64 cur_time_ms = (base::Time::Now() - base::Time()).InMilliseconds(); | |
285 | |
286 int64 cur_time_ticks_ms = | |
287 (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds(); | |
288 | |
289 // If we add this number to a time tick value, it gives the timestamp. | |
290 int64 tick_to_time_ms = cur_time_ms - cur_time_ticks_ms; | |
291 | |
292 // Chrome on all platforms stores times using the Windows epoch | |
293 // (Jan 1 1601), but the javascript wants a unix epoch. | |
294 // TODO(eroman): Getting the timestamp relative to the unix epoch should | |
295 // be part of the time library. | |
296 const int64 kUnixEpochMs = 11644473600000LL; | |
297 int64 tick_to_unix_time_ms = tick_to_time_ms - kUnixEpochMs; | |
298 | |
299 // Pass it as a string, since it may be too large to fit in an integer. | |
300 constants_dict->SetString("timeTickOffset", | |
301 base::Int64ToString(tick_to_unix_time_ms)); | |
302 } | |
303 | |
304 // "clientInfo" key is required for some NetLogLogger log readers. | |
305 // Provide a default empty value for compatibility. | |
306 constants_dict->Set("clientInfo", new base::DictionaryValue()); | |
307 | |
308 // Add a list of active field experiments. | |
309 { | |
310 base::FieldTrial::ActiveGroups active_groups; | |
311 base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups); | |
312 base::ListValue* field_trial_groups = new base::ListValue(); | |
313 for (base::FieldTrial::ActiveGroups::const_iterator it = | |
314 active_groups.begin(); | |
315 it != active_groups.end(); ++it) { | |
316 field_trial_groups->AppendString(it->trial_name + ":" + | |
317 it->group_name); | |
318 } | |
319 constants_dict->Set("activeFieldTrialGroups", field_trial_groups); | |
320 } | |
321 | |
322 return constants_dict.Pass(); | |
323 } | |
324 | |
325 NET_EXPORT scoped_ptr<base::DictionaryValue> GetNetInfo( | |
326 URLRequestContext* context, int info_sources) { | |
327 // May only be called on the context's thread. | |
328 DCHECK(context->CalledOnValidThread()); | |
329 | |
330 scoped_ptr<base::DictionaryValue> net_info_dict(new base::DictionaryValue()); | |
331 | |
332 // TODO(mmenke): The code for most of these sources should probably be moved | |
333 // into the sources themselves. | |
334 if (info_sources & NET_INFO_PROXY_SETTINGS) { | |
335 net::ProxyService* proxy_service = context->proxy_service(); | |
336 | |
337 base::DictionaryValue* dict = new base::DictionaryValue(); | |
338 if (proxy_service->fetched_config().is_valid()) | |
339 dict->Set("original", proxy_service->fetched_config().ToValue()); | |
340 if (proxy_service->config().is_valid()) | |
341 dict->Set("effective", proxy_service->config().ToValue()); | |
342 | |
343 net_info_dict->Set(NetInfoSourceToString(NET_INFO_PROXY_SETTINGS), dict); | |
344 } | |
345 | |
346 if (info_sources & NET_INFO_BAD_PROXIES) { | |
347 const net::ProxyRetryInfoMap& bad_proxies_map = | |
348 context->proxy_service()->proxy_retry_info(); | |
349 | |
350 base::ListValue* list = new base::ListValue(); | |
351 | |
352 for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin(); | |
353 it != bad_proxies_map.end(); ++it) { | |
354 const std::string& proxy_uri = it->first; | |
355 const net::ProxyRetryInfo& retry_info = it->second; | |
356 | |
357 base::DictionaryValue* dict = new base::DictionaryValue(); | |
358 dict->SetString("proxy_uri", proxy_uri); | |
359 dict->SetString("bad_until", | |
360 net::NetLog::TickCountToString(retry_info.bad_until)); | |
361 | |
362 list->Append(dict); | |
363 } | |
364 | |
365 net_info_dict->Set(NetInfoSourceToString(NET_INFO_BAD_PROXIES), list); | |
366 } | |
367 | |
368 if (info_sources & NET_INFO_HOST_RESOLVER) { | |
369 net::HostResolver* host_resolver = context->host_resolver(); | |
370 DCHECK(host_resolver); | |
371 net::HostCache* cache = host_resolver->GetHostCache(); | |
372 if (cache) { | |
373 base::DictionaryValue* dict = new base::DictionaryValue(); | |
374 base::Value* dns_config = host_resolver->GetDnsConfigAsValue(); | |
375 if (dns_config) | |
376 dict->Set("dns_config", dns_config); | |
377 | |
378 dict->SetInteger( | |
379 "default_address_family", | |
380 static_cast<int>(host_resolver->GetDefaultAddressFamily())); | |
381 | |
382 base::DictionaryValue* cache_info_dict = new base::DictionaryValue(); | |
383 | |
384 cache_info_dict->SetInteger( | |
385 "capacity", | |
386 static_cast<int>(cache->max_entries())); | |
387 | |
388 base::ListValue* entry_list = new base::ListValue(); | |
389 | |
390 net::HostCache::EntryMap::Iterator it(cache->entries()); | |
391 for (; it.HasNext(); it.Advance()) { | |
392 const net::HostCache::Key& key = it.key(); | |
393 const net::HostCache::Entry& entry = it.value(); | |
394 | |
395 base::DictionaryValue* entry_dict = new base::DictionaryValue(); | |
396 | |
397 entry_dict->SetString("hostname", key.hostname); | |
398 entry_dict->SetInteger("address_family", | |
399 static_cast<int>(key.address_family)); | |
400 entry_dict->SetString("expiration", | |
401 net::NetLog::TickCountToString(it.expiration())); | |
402 | |
403 if (entry.error != net::OK) { | |
404 entry_dict->SetInteger("error", entry.error); | |
405 } else { | |
406 // Append all of the resolved addresses. | |
407 base::ListValue* address_list = new base::ListValue(); | |
408 for (size_t i = 0; i < entry.addrlist.size(); ++i) { | |
409 address_list->AppendString(entry.addrlist[i].ToStringWithoutPort()); | |
410 } | |
411 entry_dict->Set("addresses", address_list); | |
412 } | |
413 | |
414 entry_list->Append(entry_dict); | |
415 } | |
416 | |
417 cache_info_dict->Set("entries", entry_list); | |
418 dict->Set("cache", cache_info_dict); | |
419 net_info_dict->Set(NetInfoSourceToString(NET_INFO_HOST_RESOLVER), dict); | |
420 } | |
421 } | |
422 | |
423 net::HttpNetworkSession* http_network_session = | |
424 context->http_transaction_factory()->GetSession(); | |
425 | |
426 if (info_sources & NET_INFO_SOCKET_POOL) { | |
427 net_info_dict->Set(NetInfoSourceToString(NET_INFO_SOCKET_POOL), | |
428 http_network_session->SocketPoolInfoToValue()); | |
429 } | |
430 | |
431 if (info_sources & NET_INFO_SPDY_SESSIONS) { | |
432 net_info_dict->Set(NetInfoSourceToString(NET_INFO_SPDY_SESSIONS), | |
433 http_network_session->SpdySessionPoolInfoToValue()); | |
434 } | |
435 | |
436 if (info_sources & NET_INFO_SPDY_STATUS) { | |
437 base::DictionaryValue* status_dict = new base::DictionaryValue(); | |
438 | |
439 status_dict->SetBoolean("spdy_enabled", | |
440 net::HttpStreamFactory::spdy_enabled()); | |
441 status_dict->SetBoolean( | |
442 "use_alternate_protocols", | |
443 http_network_session->params().use_alternate_protocols); | |
444 status_dict->SetBoolean( | |
445 "force_spdy_over_ssl", | |
446 http_network_session->params().force_spdy_over_ssl); | |
447 status_dict->SetBoolean( | |
448 "force_spdy_always", | |
449 http_network_session->params().force_spdy_always); | |
450 | |
451 NextProtoVector next_protos; | |
452 http_network_session->GetNextProtos(&next_protos); | |
453 if (!next_protos.empty()) { | |
454 std::string next_protos_string; | |
455 for (const NextProto proto : next_protos) { | |
456 if (!next_protos_string.empty()) | |
457 next_protos_string.append(","); | |
458 next_protos_string.append(SSLClientSocket::NextProtoToString(proto)); | |
459 } | |
460 status_dict->SetString("next_protos", next_protos_string); | |
461 } | |
462 | |
463 net_info_dict->Set(NetInfoSourceToString(NET_INFO_SPDY_STATUS), | |
464 status_dict); | |
465 } | |
466 | |
467 if (info_sources & NET_INFO_SPDY_ALT_PROTO_MAPPINGS) { | |
468 base::ListValue* dict_list = new base::ListValue(); | |
469 | |
470 const net::HttpServerProperties& http_server_properties = | |
471 *context->http_server_properties(); | |
472 | |
473 const net::AlternateProtocolMap& map = | |
474 http_server_properties.alternate_protocol_map(); | |
475 | |
476 for (net::AlternateProtocolMap::const_iterator it = map.begin(); | |
477 it != map.end(); ++it) { | |
478 base::DictionaryValue* dict = new base::DictionaryValue(); | |
479 dict->SetString("host_port_pair", it->first.ToString()); | |
480 dict->SetString("alternate_protocol", it->second.ToString()); | |
481 dict_list->Append(dict); | |
482 } | |
483 | |
484 net_info_dict->Set(NetInfoSourceToString(NET_INFO_SPDY_ALT_PROTO_MAPPINGS), | |
485 dict_list); | |
486 } | |
487 | |
488 if (info_sources & NET_INFO_QUIC) { | |
489 net_info_dict->Set(NetInfoSourceToString(NET_INFO_QUIC), | |
490 http_network_session->QuicInfoToValue()); | |
491 } | |
492 | |
493 if (info_sources & NET_INFO_HTTP_CACHE) { | |
494 base::DictionaryValue* info_dict = new base::DictionaryValue(); | |
495 base::DictionaryValue* stats_dict = new base::DictionaryValue(); | |
496 | |
497 disk_cache::Backend* disk_cache = GetDiskCacheBackend(context); | |
498 | |
499 if (disk_cache) { | |
500 // Extract the statistics key/value pairs from the backend. | |
501 base::StringPairs stats; | |
502 disk_cache->GetStats(&stats); | |
503 for (size_t i = 0; i < stats.size(); ++i) { | |
504 stats_dict->SetStringWithoutPathExpansion( | |
505 stats[i].first, stats[i].second); | |
506 } | |
507 } | |
508 info_dict->Set("stats", stats_dict); | |
509 | |
510 net_info_dict->Set(NetInfoSourceToString(NET_INFO_HTTP_CACHE), | |
511 info_dict); | |
512 } | |
513 | |
514 if (info_sources & NET_INFO_SDCH) { | |
515 base::Value* info_dict; | |
516 SdchManager* sdch_manager = context->sdch_manager(); | |
517 if (sdch_manager) { | |
518 info_dict = sdch_manager->SdchInfoToValue(); | |
519 } else { | |
520 info_dict = new base::DictionaryValue(); | |
521 } | |
522 net_info_dict->Set(NetInfoSourceToString(NET_INFO_SDCH), info_dict); | |
523 } | |
524 | |
525 return net_info_dict.Pass(); | |
526 } | |
527 | |
528 NET_EXPORT void CreateNetLogEntriesForActiveObjects( | |
529 const std::set<URLRequestContext*>& contexts, | |
530 NetLog::ThreadSafeObserver* observer) { | |
531 // Not safe to call this when the observer is watching a NetLog. | |
532 DCHECK(!observer->net_log()); | |
533 | |
534 // Put together the list of all requests. | |
535 std::vector<const URLRequest*> requests; | |
536 for (const auto& context : contexts) { | |
537 // May only be called on the context's thread. | |
538 DCHECK(context->CalledOnValidThread()); | |
539 // Contexts should all be using the same NetLog. | |
540 DCHECK_EQ((*contexts.begin())->net_log(), context->net_log()); | |
541 for (const auto& request : *context->url_requests()) { | |
542 requests.push_back(request); | |
543 } | |
544 } | |
545 | |
546 // Sort by creation time. | |
547 std::sort(requests.begin(), requests.end(), RequestCreatedBefore); | |
548 | |
549 // Create fake events. | |
550 ScopedVector<NetLog::Entry> entries; | |
551 for (const auto& request : requests) { | |
552 net::NetLog::ParametersCallback callback = | |
553 base::Bind(&GetRequestStateAsValue, base::Unretained(request)); | |
554 | |
555 net::NetLog::EntryData entry_data(net::NetLog::TYPE_REQUEST_ALIVE, | |
556 request->net_log().source(), | |
557 net::NetLog::PHASE_BEGIN, | |
558 request->creation_time(), | |
559 &callback); | |
560 NetLog::Entry entry(&entry_data, request->net_log().GetLogLevel()); | |
561 observer->OnAddEntry(entry); | |
562 } | |
563 } | |
564 | |
565 } // namespace net | |
OLD | NEW |