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

Side by Side Diff: chrome/browser/net/view_net_internals_job_factory.cc

Issue 2008007: Replace about:net-internals with the javascript-based frontend.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: improve a comment Created 10 years, 7 months 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) 2010 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 "chrome/browser/net/view_net_internals_job_factory.h"
6
7 #include <sstream>
8
9 #include "base/format_macros.h"
10 #include "base/stl_util-inl.h"
11 #include "base/string_util.h"
12 #include "chrome/browser/net/chrome_net_log.h"
13 #include "chrome/browser/net/chrome_url_request_context.h"
14 #include "chrome/browser/net/passive_log_collector.h"
15 #include "chrome/common/url_constants.h"
16 #include "net/base/escape.h"
17 #include "net/base/host_resolver_impl.h"
18 #include "net/base/net_errors.h"
19 #include "net/base/net_log_util.h"
20 #include "net/base/net_util.h"
21 #include "net/base/sys_addrinfo.h"
22 #include "net/proxy/proxy_service.h"
23 #include "net/socket_stream/socket_stream.h"
24 #include "net/url_request/url_request.h"
25 #include "net/url_request/url_request_context.h"
26 #include "net/url_request/url_request_simple_job.h"
27 #include "net/url_request/view_cache_helper.h"
28
29 namespace {
30
31 const char kViewHttpCacheSubPath[] = "view-cache";
32
33 // TODO(eroman): Delete this file. It should be replaced by
34 // chrome/browser/dom_ui/net_internals_ui.cc once the porting is
35 // complete.
36
37 PassiveLogCollector* GetPassiveLogCollector(URLRequestContext* context) {
38 // Really this is the same as:
39 // g_browser_process->io_thread()->globals()->
40 // net_log.get()
41 // (But we can't access g_browser_process from the IO thread).
42 ChromeNetLog* chrome_net_log = static_cast<ChromeNetLog*>(
43 static_cast<ChromeURLRequestContext*>(context)->net_log());
44 return chrome_net_log->passive_collector();
45 }
46
47 PassiveLogCollector::RequestTracker* GetURLRequestTracker(
48 URLRequestContext* context) {
49 return GetPassiveLogCollector(context)->url_request_tracker();
50 }
51
52 PassiveLogCollector::RequestTracker* GetSocketStreamTracker(
53 URLRequestContext* context) {
54 return GetPassiveLogCollector(context)->socket_stream_tracker();
55 }
56
57 PassiveLogCollector::InitProxyResolverTracker* GetInitProxyResolverTracker(
58 URLRequestContext* context) {
59 return GetPassiveLogCollector(context)->init_proxy_resolver_tracker();
60 }
61
62 std::string GetDetails(const GURL& url) {
63 DCHECK(ViewNetInternalsJobFactory::IsSupportedURL(url));
64 size_t start = strlen(chrome::kNetworkViewInternalsURL);
65 if (start >= url.spec().size())
66 return std::string();
67 return url.spec().substr(start);
68 }
69
70 GURL MakeURL(const std::string& details) {
71 return GURL(std::string(chrome::kNetworkViewInternalsURL) + details);
72 }
73
74 // Converts a PassiveLogCollector::EntryList to a CapturingNetLog::EntryList.
75 //
76 // They are basically the same thing, except PassiveLogCollector has an extra
77 // "order" field which we will drop.
78 net::CapturingNetLog::EntryList ConvertEntryList(
79 const PassiveLogCollector::EntryList& input) {
80 net::CapturingNetLog::EntryList result;
81 for (size_t i = 0; i < input.size(); ++i) {
82 result.push_back(
83 net::CapturingNetLog::Entry(
84 input[i].type,
85 input[i].time,
86 input[i].source,
87 input[i].phase,
88 input[i].extra_parameters));
89 }
90 return result;
91 }
92
93 // A job subclass that implements a protocol to inspect the internal
94 // state of the network stack.
95 class ViewNetInternalsJob : public URLRequestSimpleJob {
96 public:
97
98 explicit ViewNetInternalsJob(URLRequest* request)
99 : URLRequestSimpleJob(request) {}
100
101 // URLRequestSimpleJob methods:
102 virtual bool GetData(std::string* mime_type,
103 std::string* charset,
104 std::string* data) const;
105
106 // Overridden methods from URLRequestJob:
107 virtual bool IsRedirectResponse(GURL* location, int* http_status_code);
108
109 private:
110 ~ViewNetInternalsJob() {}
111
112 // Returns true if the current request is for a "view-cache" URL.
113 // If it is, then |key| is assigned the particular cache URL of the request.
114 bool GetViewCacheKeyForRequest(std::string* key) const;
115 };
116
117 //------------------------------------------------------------------------------
118 // Format helpers.
119 //------------------------------------------------------------------------------
120
121 void OutputTextInPre(const std::string& text, std::string* out) {
122 out->append("<pre>");
123 out->append(EscapeForHTML(text));
124 out->append("</pre>");
125 }
126
127 // Appends an input button to |data| with text |title| that sends the command
128 // string |command| back to the browser, and then refreshes the page.
129 void DrawCommandButton(const std::string& title,
130 const std::string& command,
131 std::string* data) {
132 StringAppendF(data, "<input type=\"button\" value=\"%s\" "
133 "onclick=\"DoCommand('%s')\" />",
134 title.c_str(),
135 command.c_str());
136 }
137
138 //------------------------------------------------------------------------------
139 // URLRequestContext helpers.
140 //------------------------------------------------------------------------------
141
142 net::HostResolverImpl* GetHostResolverImpl(URLRequestContext* context) {
143 return context->host_resolver()->GetAsHostResolverImpl();
144 }
145
146 net::HostCache* GetHostCache(URLRequestContext* context) {
147 if (GetHostResolverImpl(context))
148 return GetHostResolverImpl(context)->cache();
149 return NULL;
150 }
151
152 //------------------------------------------------------------------------------
153 // Subsection definitions.
154 //------------------------------------------------------------------------------
155
156 class SubSection {
157 public:
158 // |name| is the URL path component for this subsection.
159 // |title| is the textual description.
160 SubSection(SubSection* parent, const char* name, const char* title)
161 : parent_(parent),
162 name_(name),
163 title_(title) {
164 }
165
166 virtual ~SubSection() {
167 STLDeleteContainerPointers(children_.begin(), children_.end());
168 }
169
170 // Outputs the subsection's contents to |out|.
171 virtual void OutputBody(URLRequestContext* context, std::string* out) {}
172
173 // Outputs this subsection, and all of its children.
174 void OutputRecursive(URLRequestContext* context, std::string* out) {
175 if (!is_root()) {
176 // Canonicalizing the URL escapes characters which cause problems in HTML.
177 std::string section_url = MakeURL(GetFullyQualifiedName()).spec();
178
179 // Print the heading.
180 StringAppendF(
181 out,
182 "<div>"
183 "<span class=subsection_title>%s</span> "
184 "<span class=subsection_name>(<a href='%s'>%s</a>)<span>"
185 "</div>",
186 EscapeForHTML(title_).c_str(),
187 section_url.c_str(),
188 EscapeForHTML(section_url).c_str());
189
190 out->append("<div class=subsection_body>");
191 }
192
193 OutputBody(context, out);
194
195 for (size_t i = 0; i < children_.size(); ++i)
196 children_[i]->OutputRecursive(context, out);
197
198 if (!is_root())
199 out->append("</div>");
200 }
201
202 // Returns the SubSection contained by |this| with fully qualified name
203 // |dotted_name|, or NULL if none was found.
204 SubSection* FindSubSectionByName(const std::string& dotted_name) {
205 if (dotted_name == "")
206 return this;
207
208 std::string child_name;
209 std::string child_sub_name;
210
211 size_t split_pos = dotted_name.find('.');
212 if (split_pos == std::string::npos) {
213 child_name = dotted_name;
214 child_sub_name = std::string();
215 } else {
216 child_name = dotted_name.substr(0, split_pos);
217 child_sub_name = dotted_name.substr(split_pos + 1);
218 }
219
220 for (size_t i = 0; i < children_.size(); ++i) {
221 if (children_[i]->name_ == child_name)
222 return children_[i]->FindSubSectionByName(child_sub_name);
223 }
224
225 return NULL; // Not found.
226 }
227
228 std::string GetFullyQualifiedName() {
229 if (!parent_)
230 return name_;
231
232 std::string parent_name = parent_->GetFullyQualifiedName();
233 if (parent_name.empty())
234 return name_;
235
236 return parent_name + "." + name_;
237 }
238
239 bool is_root() const {
240 return parent_ == NULL;
241 }
242
243 protected:
244 typedef std::vector<SubSection*> SubSectionList;
245
246 void AddSubSection(SubSection* subsection) {
247 children_.push_back(subsection);
248 }
249
250 SubSection* parent_;
251 std::string name_;
252 std::string title_;
253
254 SubSectionList children_;
255 };
256
257 class ProxyServiceCurrentConfigSubSection : public SubSection {
258 public:
259 explicit ProxyServiceCurrentConfigSubSection(SubSection* parent)
260 : SubSection(parent, "config", "Current configuration") {
261 }
262
263 virtual void OutputBody(URLRequestContext* context, std::string* out) {
264 DrawCommandButton("Force reload", "reload-proxy-config", out);
265
266 net::ProxyService* proxy_service = context->proxy_service();
267 if (proxy_service->config_has_been_initialized()) {
268 // net::ProxyConfig defines an operator<<.
269 std::ostringstream stream;
270 stream << proxy_service->config();
271 OutputTextInPre(stream.str(), out);
272 } else {
273 out->append("<i>Not yet initialized</i>");
274 }
275 }
276 };
277
278 class ProxyServiceLastInitLogSubSection : public SubSection {
279 public:
280 explicit ProxyServiceLastInitLogSubSection(SubSection* parent)
281 : SubSection(parent, "init_log", "Last initialized load log") {
282 }
283
284 virtual void OutputBody(URLRequestContext* context, std::string* out) {
285 OutputTextInPre(
286 net::NetLogUtil::PrettyPrintAsEventTree(
287 ConvertEntryList(GetInitProxyResolverTracker(context)->entries()),
288 0),
289 out);
290 }
291 };
292
293 class ProxyServiceBadProxiesSubSection : public SubSection {
294 public:
295 explicit ProxyServiceBadProxiesSubSection(SubSection* parent)
296 : SubSection(parent, "bad_proxies", "Bad Proxies") {
297 }
298
299 virtual void OutputBody(URLRequestContext* context, std::string* out) {
300 net::ProxyService* proxy_service = context->proxy_service();
301 const net::ProxyRetryInfoMap& bad_proxies_map =
302 proxy_service->proxy_retry_info();
303
304 DrawCommandButton("Clear", "clear-badproxies", out);
305
306 out->append("<table border=1>");
307 out->append("<tr><th>Bad proxy server</th>"
308 "<th>Remaining time until retry (ms)</th></tr>");
309
310 for (net::ProxyRetryInfoMap::const_iterator it = bad_proxies_map.begin();
311 it != bad_proxies_map.end(); ++it) {
312 const std::string& proxy_uri = it->first;
313 const net::ProxyRetryInfo& retry_info = it->second;
314
315 // Note that ttl_ms may be negative, for the cases where entries have
316 // expired but not been garbage collected yet.
317 int ttl_ms = static_cast<int>(
318 (retry_info.bad_until - base::TimeTicks::Now()).InMilliseconds());
319
320 // Color expired entries blue.
321 if (ttl_ms > 0)
322 out->append("<tr>");
323 else
324 out->append("<tr style='color:blue'>");
325
326 StringAppendF(out, "<td>%s</td><td>%d</td>",
327 EscapeForHTML(proxy_uri).c_str(),
328 ttl_ms);
329
330 out->append("</tr>");
331 }
332 out->append("</table>");
333 }
334 };
335
336 class ProxyServiceSubSection : public SubSection {
337 public:
338 explicit ProxyServiceSubSection(SubSection* parent)
339 : SubSection(parent, "proxyservice", "ProxyService") {
340 AddSubSection(new ProxyServiceCurrentConfigSubSection(this));
341 AddSubSection(new ProxyServiceLastInitLogSubSection(this));
342 AddSubSection(new ProxyServiceBadProxiesSubSection(this));
343 }
344 };
345
346 class HostResolverCacheSubSection : public SubSection {
347 public:
348 explicit HostResolverCacheSubSection(SubSection* parent)
349 : SubSection(parent, "hostcache", "HostCache") {
350 }
351
352 virtual void OutputBody(URLRequestContext* context, std::string* out) {
353 const net::HostCache* host_cache = GetHostCache(context);
354
355 if (!host_cache || host_cache->caching_is_disabled()) {
356 out->append("<i>Caching is disabled.</i>");
357 return;
358 }
359
360 DrawCommandButton("Clear", "clear-hostcache", out);
361
362 StringAppendF(
363 out,
364 "<ul><li>Size: %" PRIuS "</li>"
365 "<li>Capacity: %" PRIuS "</li>"
366 "<li>Time to live (ms) for success entries: %" PRId64"</li>"
367 "<li>Time to live (ms) for failure entries: %" PRId64"</li></ul>",
368 host_cache->size(),
369 host_cache->max_entries(),
370 host_cache->success_entry_ttl().InMilliseconds(),
371 host_cache->failure_entry_ttl().InMilliseconds());
372
373 out->append("<table border=1>"
374 "<tr>"
375 "<th>Host</th>"
376 "<th>Address family</th>"
377 "<th>Address list</th>"
378 "<th>Canonical name</th>"
379 "<th>Time to live (ms)</th>"
380 "</tr>");
381
382 for (net::HostCache::EntryMap::const_iterator it =
383 host_cache->entries().begin();
384 it != host_cache->entries().end();
385 ++it) {
386 const net::HostCache::Key& key = it->first;
387 const net::HostCache::Entry* entry = it->second.get();
388
389 std::string address_family_str =
390 AddressFamilyToString(key.address_family);
391
392 // Note that ttl_ms may be negative, for the cases where entries have
393 // expired but not been garbage collected yet.
394 int ttl_ms = static_cast<int>(
395 (entry->expiration - base::TimeTicks::Now()).InMilliseconds());
396
397 // Color expired entries blue.
398 if (ttl_ms > 0) {
399 out->append("<tr>");
400 } else {
401 out->append("<tr style='color:blue'>");
402 }
403
404 // Stringify all of the addresses in the address list, separated
405 // by newlines (br).
406 std::string address_list_html;
407 std::string canonical_name_html;
408
409 if (entry->error != net::OK) {
410 address_list_html = "<span style='font-weight: bold; color:red'>" +
411 EscapeForHTML(net::ErrorToString(entry->error)) +
412 "</span>";
413 } else {
414 const struct addrinfo* current_address = entry->addrlist.head();
415 while (current_address) {
416 if (!address_list_html.empty())
417 address_list_html += "<br>";
418 address_list_html += EscapeForHTML(
419 net::NetAddressToString(current_address));
420 current_address = current_address->ai_next;
421 }
422 std::string canonical_name;
423 if (entry->addrlist.GetCanonicalName(&canonical_name))
424 canonical_name_html = EscapeForHTML(canonical_name);
425 }
426
427 StringAppendF(out,
428 "<td>%s</td><td>%s</td><td>%s</td>"
429 "<td>%s</td><td>%d</td></tr>",
430 EscapeForHTML(key.hostname).c_str(),
431 EscapeForHTML(address_family_str).c_str(),
432 address_list_html.c_str(),
433 canonical_name_html.c_str(),
434 ttl_ms);
435 }
436
437 out->append("</table>");
438 }
439
440 static std::string AddressFamilyToString(net::AddressFamily address_family) {
441 switch (address_family) {
442 case net::ADDRESS_FAMILY_IPV4:
443 return "IPV4";
444 case net::ADDRESS_FAMILY_IPV6:
445 return "IPV6";
446 case net::ADDRESS_FAMILY_UNSPECIFIED:
447 return "UNSPECIFIED";
448 default:
449 NOTREACHED();
450 return "???";
451 }
452 }
453 };
454
455 class HostResolverTraceSubSection : public SubSection {
456 public:
457 explicit HostResolverTraceSubSection(SubSection* parent)
458 : SubSection(parent, "trace", "Trace of requests") {
459 }
460
461 virtual void OutputBody(URLRequestContext* context, std::string* out) {
462 net::HostResolverImpl* resolver = GetHostResolverImpl(context);
463 if (!resolver) {
464 out->append("<i>Tracing is not supported by this resolver.</i>");
465 return;
466 }
467
468 DrawCommandButton("Clear", "clear-hostresolver-trace", out);
469
470 if (resolver->IsRequestsTracingEnabled()) {
471 DrawCommandButton("Disable tracing", "hostresolver-trace-disable", out);
472 } else {
473 DrawCommandButton("Enable tracing", "hostresolver-trace-enable", out);
474 }
475
476 net::CapturingNetLog::EntryList entries;
477 if (resolver->GetRequestsTrace(&entries)) {
478 out->append(
479 "<p>To make sense of this trace, process it with the Python script "
480 "formatter.py at "
481 "<a href='http://src.chromium.org/viewvc/chrome/trunk/src/net/tools/"
482 "dns_trace_formatter/'>net/tools/dns_trace_formatter</a></p>");
483 OutputTextInPre(net::NetLogUtil::PrettyPrintAsEventTree(entries, 0),
484 out);
485 } else {
486 out->append("<p><i>No trace information, must enable tracing.</i></p>");
487 }
488 }
489 };
490
491 class HostResolverSubSection : public SubSection {
492 public:
493 explicit HostResolverSubSection(SubSection* parent)
494 : SubSection(parent, "hostresolver", "HostResolver") {
495 AddSubSection(new HostResolverCacheSubSection(this));
496 AddSubSection(new HostResolverTraceSubSection(this));
497 }
498 };
499
500 // Helper for the URLRequest "outstanding" and "live" sections.
501 void OutputURLAndLoadLog(const PassiveLogCollector::RequestInfo& request,
502 std::string* out) {
503 out->append("<li>");
504 out->append("<nobr>");
505 out->append(EscapeForHTML(request.url));
506 out->append("</nobr>");
507 OutputTextInPre(
508 net::NetLogUtil::PrettyPrintAsEventTree(
509 ConvertEntryList(request.entries),
510 request.num_entries_truncated),
511 out);
512 out->append("</li>");
513 }
514
515 class URLRequestLiveSubSection : public SubSection {
516 public:
517 explicit URLRequestLiveSubSection(SubSection* parent)
518 : SubSection(parent, "outstanding", "Outstanding requests") {
519 }
520
521 virtual void OutputBody(URLRequestContext* context, std::string* out) {
522 PassiveLogCollector::RequestInfoList requests =
523 GetURLRequestTracker(context)->GetLiveRequests();
524
525 out->append("<ol>");
526 for (size_t i = 0; i < requests.size(); ++i) {
527 // Reverse the list order, so we display from most recent to oldest.
528 size_t index = requests.size() - i - 1;
529 OutputURLAndLoadLog(requests[index], out);
530 }
531 out->append("</ol>");
532 }
533 };
534
535 class URLRequestRecentSubSection : public SubSection {
536 public:
537 explicit URLRequestRecentSubSection(SubSection* parent)
538 : SubSection(parent, "recent", "Recently completed requests") {
539 }
540
541 virtual void OutputBody(URLRequestContext* context, std::string* out) {
542 PassiveLogCollector::RequestInfoList recent =
543 GetURLRequestTracker(context)->GetRecentlyDeceased();
544
545 DrawCommandButton("Clear", "clear-urlrequest-graveyard", out);
546
547 out->append("<ol>");
548 for (size_t i = 0; i < recent.size(); ++i) {
549 // Reverse the list order, so we dispay from most recent to oldest.
550 size_t index = recent.size() - i - 1;
551 OutputURLAndLoadLog(recent[index], out);
552 }
553 out->append("</ol>");
554 }
555 };
556
557 class URLRequestSubSection : public SubSection {
558 public:
559 explicit URLRequestSubSection(SubSection* parent)
560 : SubSection(parent, "urlrequest", "URLRequest") {
561 AddSubSection(new URLRequestLiveSubSection(this));
562 AddSubSection(new URLRequestRecentSubSection(this));
563 }
564 };
565
566 class HttpCacheStatsSubSection : public SubSection {
567 public:
568 explicit HttpCacheStatsSubSection(SubSection* parent)
569 : SubSection(parent, "stats", "Statistics") {
570 }
571
572 virtual void OutputBody(URLRequestContext* context, std::string* out) {
573 ViewCacheHelper::GetStatisticsHTML(context, out);
574 }
575 };
576
577 class HttpCacheSection : public SubSection {
578 public:
579 explicit HttpCacheSection(SubSection* parent)
580 : SubSection(parent, "httpcache", "HttpCache") {
581 AddSubSection(new HttpCacheStatsSubSection(this));
582 }
583
584 virtual void OutputBody(URLRequestContext* context, std::string* out) {
585 // Advertise the view-cache URL (too much data to inline it).
586 out->append("<p><a href='/");
587 out->append(kViewHttpCacheSubPath);
588 out->append("'>View all cache entries</a></p>");
589 }
590 };
591
592 class SocketStreamLiveSubSection : public SubSection {
593 public:
594 explicit SocketStreamLiveSubSection(SubSection* parent)
595 : SubSection(parent, "live", "Live SocketStreams") {
596 }
597
598 virtual void OutputBody(URLRequestContext* context, std::string* out) {
599 PassiveLogCollector::RequestInfoList sockets =
600 GetSocketStreamTracker(context)->GetLiveRequests();
601
602 out->append("<ol>");
603 for (size_t i = 0; i < sockets.size(); ++i) {
604 // Reverse the list order, so we dispay from most recent to oldest.
605 size_t index = sockets.size() - i - 1;
606 OutputURLAndLoadLog(sockets[index], out);
607 }
608 out->append("</ol>");
609 }
610 };
611
612 class SocketStreamRecentSubSection : public SubSection {
613 public:
614 explicit SocketStreamRecentSubSection(SubSection* parent)
615 : SubSection(parent, "recent", "Recently completed SocketStreams") {
616 }
617
618 virtual void OutputBody(URLRequestContext* context, std::string* out) {
619 PassiveLogCollector::RequestInfoList recent =
620 GetSocketStreamTracker(context)->GetRecentlyDeceased();
621
622 DrawCommandButton("Clear", "clear-socketstream-graveyard", out);
623
624 out->append("<ol>");
625 for (size_t i = 0; i < recent.size(); ++i) {
626 // Reverse the list order, so we dispay from most recent to oldest.
627 size_t index = recent.size() - i - 1;
628 OutputURLAndLoadLog(recent[index], out);
629 }
630 out->append("</ol>");
631 }
632 };
633
634 class SocketStreamSubSection : public SubSection {
635 public:
636 explicit SocketStreamSubSection(SubSection* parent)
637 : SubSection(parent, "socketstream", "SocketStream") {
638 AddSubSection(new SocketStreamLiveSubSection(this));
639 AddSubSection(new SocketStreamRecentSubSection(this));
640 }
641 };
642
643 class AllSubSections : public SubSection {
644 public:
645 AllSubSections() : SubSection(NULL, "", "") {
646 AddSubSection(new ProxyServiceSubSection(this));
647 AddSubSection(new HostResolverSubSection(this));
648 AddSubSection(new URLRequestSubSection(this));
649 AddSubSection(new HttpCacheSection(this));
650 AddSubSection(new SocketStreamSubSection(this));
651 }
652 };
653
654 bool HandleCommand(const std::string& command,
655 URLRequestContext* context) {
656 if (StartsWithASCII(command, "full-logging-", true)) {
657 bool enable_full_logging = (command == "full-logging-enable");
658 GetURLRequestTracker(context)->SetUnbounded(enable_full_logging);
659 GetSocketStreamTracker(context)->SetUnbounded(enable_full_logging);
660 return true;
661 }
662
663 if (StartsWithASCII(command, "hostresolver-trace-", true)) {
664 bool enable_tracing = (command == "hostresolver-trace-enable");
665 if (GetHostResolverImpl(context)) {
666 GetHostResolverImpl(context)->EnableRequestsTracing(enable_tracing);
667 }
668 }
669
670 if (command == "clear-urlrequest-graveyard") {
671 GetURLRequestTracker(context)->ClearRecentlyDeceased();
672 return true;
673 }
674
675 if (command == "clear-socketstream-graveyard") {
676 GetSocketStreamTracker(context)->ClearRecentlyDeceased();
677 return true;
678 }
679
680 if (command == "clear-hostcache") {
681 net::HostCache* host_cache = GetHostCache(context);
682 if (host_cache)
683 host_cache->clear();
684 return true;
685 }
686
687 if (command == "clear-badproxies") {
688 context->proxy_service()->ClearBadProxiesCache();
689 return true;
690 }
691
692 if (command == "clear-hostresolver-trace") {
693 if (GetHostResolverImpl(context))
694 GetHostResolverImpl(context)->ClearRequestsTrace();
695 }
696
697 if (command == "reload-proxy-config") {
698 context->proxy_service()->ForceReloadProxyConfig();
699 return true;
700 }
701
702 return false;
703 }
704
705 // Process any query strings in the request (for actions like toggling
706 // full logging.
707 void ProcessQueryStringCommands(URLRequestContext* context,
708 const std::string& query) {
709 if (!StartsWithASCII(query, "commands=", true)) {
710 // Not a recognized format.
711 return;
712 }
713
714 std::string commands_str = query.substr(strlen("commands="));
715 commands_str = UnescapeURLComponent(commands_str, UnescapeRule::NORMAL);
716
717 // The command list is comma-separated.
718 std::vector<std::string> commands;
719 SplitString(commands_str, ',', &commands);
720
721 for (size_t i = 0; i < commands.size(); ++i)
722 HandleCommand(commands[i], context);
723 }
724
725 // Appends some HTML controls to |data| that allow the user to enable full
726 // logging, and clear some of the already logged data.
727 void DrawControlsHeader(URLRequestContext* context, std::string* data) {
728 bool is_full_logging_enabled =
729 GetURLRequestTracker(context)->is_unbounded() &&
730 GetSocketStreamTracker(context)->is_unbounded();
731
732 data->append("<div style='margin-bottom: 10px'>");
733
734 if (is_full_logging_enabled) {
735 DrawCommandButton("Disable full logging", "full-logging-disable", data);
736 } else {
737 DrawCommandButton("Enable full logging", "full-logging-enable", data);
738 }
739
740 DrawCommandButton("Clear all data",
741 // Send a list of comma separated commands:
742 "clear-badproxies,"
743 "clear-hostcache,"
744 "clear-urlrequest-graveyard,"
745 "clear-socketstream-graveyard,"
746 "clear-hostresolver-trace",
747 data);
748
749 data->append("</div>");
750 }
751
752 bool ViewNetInternalsJob::GetData(std::string* mime_type,
753 std::string* charset,
754 std::string* data) const {
755 mime_type->assign("text/html");
756 charset->assign("UTF-8");
757
758 URLRequestContext* context =
759 static_cast<URLRequestContext*>(request_->context());
760
761 data->clear();
762
763 // Use a different handler for "view-cache/*" subpaths.
764 std::string cache_key;
765 if (GetViewCacheKeyForRequest(&cache_key)) {
766 GURL url = MakeURL(kViewHttpCacheSubPath + std::string("/"));
767 ViewCacheHelper::GetEntryInfoHTML(cache_key, context, url.spec(), data);
768 return true;
769 }
770
771 // Handle any query arguments as a command request, then redirect back to
772 // the same URL stripped of query parameters. The redirect happens as part
773 // of IsRedirectResponse().
774 if (request_->url().has_query()) {
775 ProcessQueryStringCommands(context, request_->url().query());
776 return true;
777 }
778
779 std::string details = GetDetails(request_->url());
780
781 data->append("<!DOCTYPE HTML>"
782 "<html><head><title>Network internals</title>"
783 "<style>"
784 "body { font-family: sans-serif; font-size: 0.8em; }\n"
785 "tt, code, pre { font-family: WebKitHack, monospace; }\n"
786 ".subsection_body { margin: 10px 0 10px 2em; }\n"
787 ".subsection_title { font-weight: bold; }\n"
788 "</style>"
789 "<script>\n"
790
791 // Unfortunately we can't do XHR from chrome://net-internals
792 // because the chrome:// protocol restricts access.
793 //
794 // So instead, we will send commands by doing a form
795 // submission (which as a side effect will reload the page).
796 "function DoCommand(command) {\n"
797 " document.getElementById('cmd').value = command;\n"
798 " document.getElementById('cmdsender').submit();\n"
799 "}\n"
800
801 "</script>\n"
802 "</head><body>"
803 "<form action='' method=GET id=cmdsender>"
804 "<input type='hidden' id=cmd name='commands'>"
805 "</form>"
806 "<p><a href='http://dev.chromium.org/"
807 "developers/design-documents/view-net-internals'>"
808 "Help: how do I use this?</a></p>");
809
810 DrawControlsHeader(context, data);
811
812 SubSection* all = Singleton<AllSubSections>::get();
813 SubSection* section = all;
814
815 // Display only the subsection tree asked for.
816 if (!details.empty())
817 section = all->FindSubSectionByName(details);
818
819 if (section) {
820 section->OutputRecursive(context, data);
821 } else {
822 data->append("<i>Nothing found for \"");
823 data->append(EscapeForHTML(details));
824 data->append("\"</i>");
825 }
826
827 data->append("</body></html>");
828
829 return true;
830 }
831
832 bool ViewNetInternalsJob::IsRedirectResponse(GURL* location,
833 int* http_status_code) {
834 if (request_->url().has_query() && !GetViewCacheKeyForRequest(NULL)) {
835 // Strip the query parameters.
836 GURL::Replacements replacements;
837 replacements.ClearQuery();
838 *location = request_->url().ReplaceComponents(replacements);
839 *http_status_code = 307;
840 return true;
841 }
842 return false;
843 }
844
845 bool ViewNetInternalsJob::GetViewCacheKeyForRequest(
846 std::string* key) const {
847 std::string path = GetDetails(request_->url());
848 if (!StartsWithASCII(path, kViewHttpCacheSubPath, true))
849 return false;
850
851 if (path.size() > strlen(kViewHttpCacheSubPath) &&
852 path[strlen(kViewHttpCacheSubPath)] != '/')
853 return false;
854
855 if (key && path.size() > strlen(kViewHttpCacheSubPath) + 1)
856 *key = path.substr(strlen(kViewHttpCacheSubPath) + 1);
857
858 return true;
859 }
860
861 } // namespace
862
863 // static
864 bool ViewNetInternalsJobFactory::IsSupportedURL(const GURL& url) {
865 // Note that kNetworkViewInternalsURL is terminated by a '/'.
866 return StartsWithASCII(url.spec(),
867 chrome::kNetworkViewInternalsURL,
868 true /*case_sensitive*/);
869 }
870
871 // static
872 URLRequestJob* ViewNetInternalsJobFactory::CreateJobForRequest(
873 URLRequest* request) {
874 return new ViewNetInternalsJob(request);
875 }
OLDNEW
« no previous file with comments | « chrome/browser/net/view_net_internals_job_factory.h ('k') | chrome/browser/resources/net_internals/httpcacheview.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698