Index: chrome/browser/dom_ui/net_internals_ui.cc |
=================================================================== |
--- chrome/browser/dom_ui/net_internals_ui.cc (revision 42238) |
+++ chrome/browser/dom_ui/net_internals_ui.cc (working copy) |
@@ -5,17 +5,25 @@ |
#include "chrome/browser/dom_ui/net_internals_ui.h" |
#include "app/resource_bundle.h" |
+#include "base/file_util.h" |
+#include "base/path_service.h" |
#include "base/singleton.h" |
#include "base/string_piece.h" |
+#include "base/string_util.h" |
#include "base/values.h" |
+#include "chrome/browser/browser_process.h" |
#include "chrome/browser/dom_ui/chrome_url_data_manager.h" |
#include "chrome/browser/chrome_thread.h" |
+#include "chrome/browser/io_thread.h" |
+#include "chrome/browser/net/chrome_net_log.h" |
+#include "chrome/common/chrome_paths.h" |
#include "chrome/common/url_constants.h" |
-#include "grit/browser_resources.h" |
- |
namespace { |
+// TODO(eroman): Bootstrap the net-internals page using the passively logged |
+// data. |
+ |
class NetInternalsHTMLSource : public ChromeURLDataManager::DataSource { |
public: |
NetInternalsHTMLSource(); |
@@ -72,7 +80,8 @@ |
class NetInternalsMessageHandler::IOThreadImpl |
: public base::RefCountedThreadSafe< |
NetInternalsMessageHandler::IOThreadImpl, |
- ChromeThread::DeleteOnUIThread> { |
+ ChromeThread::DeleteOnUIThread>, |
+ public ChromeNetLog::Observer { |
public: |
// Type for methods that can be used as MessageHandler callbacks. |
typedef void (IOThreadImpl::*MessageHandler)(const Value*); |
@@ -80,8 +89,11 @@ |
// Creates a proxy for |handler| that will live on the IO thread. |
// |handler| is a weak pointer, since it is possible for the DOMMessageHandler |
// to be deleted on the UI thread while we were executing on the IO thread. |
- explicit IOThreadImpl( |
- const base::WeakPtr<NetInternalsMessageHandler>& handler); |
+ // |io_thread| is the global IOThread (it is passed in as an argument since |
+ // we need to grab it from the UI thread). |
+ IOThreadImpl( |
+ const base::WeakPtr<NetInternalsMessageHandler>& handler, |
+ IOThread* io_thread); |
~IOThreadImpl(); |
@@ -91,9 +103,6 @@ |
// on the IO thread. |
DOMUI::MessageCallback* CreateCallback(MessageHandler method); |
- // Called once the DOMUI has attached to the renderer, on the IO thread. |
- void Attach(); |
- |
// Called once the DOMUI has been deleted (i.e. renderer went away), on the |
// IO thread. |
void Detach(); |
@@ -102,9 +111,13 @@ |
// Javascript message handlers: |
//-------------------------------- |
- // TODO(eroman): This is temporary! |
- void OnTestMessage(const Value* value); |
+ // This message is called after the webpage's onloaded handler has fired. |
+ // it indicates that the renderer is ready to start receiving captured data. |
+ void OnRendererReady(const Value* value); |
+ // ChromeNetLog::Observer implementation: |
+ virtual void OnAddEntry(const net::NetLog::Entry& entry); |
+ |
private: |
class CallbackHelper; |
@@ -120,6 +133,12 @@ |
// Pointer to the UI-thread message handler. Only access this from |
// the UI thread. |
base::WeakPtr<NetInternalsMessageHandler> handler_; |
+ |
+ // The global IOThread, which contains the global NetLog to observer. |
+ IOThread* io_thread_; |
+ |
+ // True if we have attached an observer to the NetLog already. |
+ bool is_observing_log_; |
friend class base::RefCountedThreadSafe<IOThreadImpl>; |
}; |
@@ -169,19 +188,30 @@ |
void NetInternalsHTMLSource::StartDataRequest(const std::string& path, |
bool is_off_the_record, |
int request_id) { |
- // Serve up the HTML contained in the resource bundle. |
- base::StringPiece html( |
- ResourceBundle::GetSharedInstance().GetRawDataResource( |
- IDR_NET_INTERNALS_HTML)); |
+ // The provided |path| identifies a file in resources/net_internals/. |
+ std::string data_string; |
+ FilePath file_path; |
+ PathService::Get(chrome::DIR_NET_INTERNALS, &file_path); |
+ std::string filename = path.empty() ? "index.html" : path; |
+ file_path = file_path.AppendASCII(filename); |
- scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); |
- html_bytes->data.resize(html.size()); |
- std::copy(html.begin(), html.end(), html_bytes->data.begin()); |
+ if (!file_util::ReadFileToString(file_path, &data_string)) { |
+ LOG(WARNING) << "Could not read resource: " << file_path.value(); |
+ data_string = StringPrintf( |
+ "Failed to read file RESOURCES/net_internals/%s", |
+ filename.c_str()); |
+ } |
- SendResponse(request_id, html_bytes); |
+ scoped_refptr<RefCountedBytes> bytes(new RefCountedBytes); |
+ bytes->data.resize(data_string.size()); |
+ std::copy(data_string.begin(), data_string.end(), bytes->data.begin()); |
+ |
+ SendResponse(request_id, bytes); |
} |
std::string NetInternalsHTMLSource::GetMimeType(const std::string&) const { |
+ // TODO(eroman): This is incorrect -- some of the subresources may be |
+ // css/javascript. |
return "text/html"; |
} |
@@ -203,23 +233,16 @@ |
DOMMessageHandler* NetInternalsMessageHandler::Attach(DOMUI* dom_ui) { |
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
- proxy_ = new IOThreadImpl(this->AsWeakPtr()); |
- |
+ proxy_ = new IOThreadImpl(this->AsWeakPtr(), g_browser_process->io_thread()); |
DOMMessageHandler* result = DOMMessageHandler::Attach(dom_ui); |
- |
- // Notify the handler on the IO thread that a renderer is attached. |
- ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, |
- NewRunnableMethod(proxy_.get(), &IOThreadImpl::Attach)); |
- |
return result; |
} |
void NetInternalsMessageHandler::RegisterMessages() { |
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
- // TODO(eroman): Register message handlers here. |
- dom_ui_->RegisterMessageCallback("testMessage", |
- proxy_->CreateCallback(&IOThreadImpl::OnTestMessage)); |
+ dom_ui_->RegisterMessageCallback("notifyReady", |
+ proxy_->CreateCallback(&IOThreadImpl::OnRendererReady)); |
} |
void NetInternalsMessageHandler::CallJavascriptFunction( |
@@ -236,8 +259,11 @@ |
//////////////////////////////////////////////////////////////////////////////// |
NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl( |
- const base::WeakPtr<NetInternalsMessageHandler>& handler) |
- : handler_(handler) { |
+ const base::WeakPtr<NetInternalsMessageHandler>& handler, |
+ IOThread* io_thread) |
+ : handler_(handler), |
+ io_thread_(io_thread), |
+ is_observing_log_(false) { |
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
} |
@@ -252,40 +278,133 @@ |
return new CallbackHelper(this, method); |
} |
-void NetInternalsMessageHandler::IOThreadImpl::Attach() { |
- DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
- // TODO(eroman): Register with network stack to observe events. |
-} |
- |
void NetInternalsMessageHandler::IOThreadImpl::Detach() { |
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
- // TODO(eroman): Unregister with network stack to observe events. |
+ // Unregister with network stack to observe events. |
+ if (is_observing_log_) |
+ io_thread_->globals()->net_log->RemoveObserver(this); |
} |
-void NetInternalsMessageHandler::IOThreadImpl::OnTestMessage( |
+void NetInternalsMessageHandler::IOThreadImpl::OnRendererReady( |
const Value* value) { |
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
+ DCHECK(!is_observing_log_) << "notifyReady called twice"; |
- // TODO(eroman): This is just a temporary method, to see something in |
- // action. We expect to have been called with an array |
- // containing 1 string, and print it to the screen. |
- std::string str; |
- if (value && value->GetType() == Value::TYPE_LIST) { |
- const ListValue* list_value = static_cast<const ListValue*>(value); |
- Value* list_member; |
- if (list_value->Get(0, &list_member) && |
- list_member->GetType() == Value::TYPE_STRING) { |
- const StringValue* string_value = |
- static_cast<const StringValue*>(list_member); |
- string_value->GetAsString(&str); |
+ // Register with network stack to observe events. |
+ is_observing_log_ = true; |
+ io_thread_->globals()->net_log->AddObserver(this); |
+ |
+ // Tell the javascript about the relationship between event type enums and |
+ // their symbolic name. |
+ { |
+ std::vector<net::NetLog::EventType> event_types = |
+ net::NetLog::GetAllEventTypes(); |
+ |
+ DictionaryValue* dict = new DictionaryValue(); |
+ |
+ for (size_t i = 0; i < event_types.size(); ++i) { |
+ const char* name = net::NetLog::EventTypeToString(event_types[i]); |
+ dict->SetInteger(ASCIIToWide(name), |
+ static_cast<int>(event_types[i])); |
} |
+ |
+ CallJavascriptFunction(L"setLogEventTypeConstants", dict); |
} |
- CallJavascriptFunction( |
- L"log", |
- Value::CreateStringValue("Browser received testMessage: " + str)); |
+ // Tell the javascript about the relationship between event phase enums and |
+ // their symbolic name. |
+ { |
+ DictionaryValue* dict = new DictionaryValue(); |
+ |
+ dict->SetInteger(L"PHASE_BEGIN", net::NetLog::PHASE_BEGIN); |
+ dict->SetInteger(L"PHASE_END", net::NetLog::PHASE_END); |
+ dict->SetInteger(L"PHASE_NONE", net::NetLog::PHASE_NONE); |
+ |
+ CallJavascriptFunction(L"setLogEventPhaseConstants", dict); |
+ } |
+ |
+ // Tell the javascript about the relationship between source type enums and |
+ // their symbolic name. |
+ // TODO(eroman): Don't duplicate the values, it will never stay up to date! |
+ { |
+ DictionaryValue* dict = new DictionaryValue(); |
+ |
+ dict->SetInteger(L"NONE", net::NetLog::SOURCE_NONE); |
+ dict->SetInteger(L"URL_REQUEST", net::NetLog::SOURCE_URL_REQUEST); |
+ dict->SetInteger(L"SOCKET_STREAM", net::NetLog::SOURCE_SOCKET_STREAM); |
+ dict->SetInteger(L"INIT_PROXY_RESOLVER", |
+ net::NetLog::SOURCE_INIT_PROXY_RESOLVER); |
+ dict->SetInteger(L"CONNECT_JOB", net::NetLog::SOURCE_CONNECT_JOB); |
+ |
+ CallJavascriptFunction(L"setLogSourceTypeConstants", dict); |
+ } |
+ |
+ // Tell the javascript about the relationship between entry type enums and |
+ // their symbolic name. |
+ { |
+ DictionaryValue* dict = new DictionaryValue(); |
+ |
+ dict->SetInteger(L"TYPE_EVENT", net::NetLog::Entry::TYPE_EVENT); |
+ dict->SetInteger(L"TYPE_STRING", net::NetLog::Entry::TYPE_STRING); |
+ dict->SetInteger(L"TYPE_ERROR_CODE", net::NetLog::Entry::TYPE_ERROR_CODE); |
+ |
+ CallJavascriptFunction(L"setLogEntryTypeConstants", dict); |
+ } |
} |
+void NetInternalsMessageHandler::IOThreadImpl::OnAddEntry( |
+ const net::NetLog::Entry& entry) { |
+ DCHECK(is_observing_log_); |
+ |
+ // JSONify the NetLog::Entry. |
+ // TODO(eroman): Need a better format for this. |
+ DictionaryValue* entry_dict = new DictionaryValue(); |
+ |
+ // Set the entry type. |
+ { |
+ net::NetLog::Entry::Type entry_type = entry.type; |
+ if (entry_type == net::NetLog::Entry::TYPE_STRING_LITERAL) |
+ entry_type = net::NetLog::Entry::TYPE_STRING; |
+ entry_dict->SetInteger(L"type", static_cast<int>(entry_type)); |
+ } |
+ |
+ // Set the entry time. |
+ entry_dict->SetInteger( |
+ L"time", |
+ static_cast<int>((entry.time - base::TimeTicks()).InMilliseconds())); |
+ |
+ // Set the entry source. |
+ DictionaryValue* source_dict = new DictionaryValue(); |
+ source_dict->SetInteger(L"id", entry.source.id); |
+ source_dict->SetInteger(L"type", static_cast<int>(entry.source.type)); |
+ entry_dict->Set(L"source", source_dict); |
+ |
+ // Set the event info (if it is an event entry). |
+ if (entry.type == net::NetLog::Entry::TYPE_EVENT) { |
+ DictionaryValue* event_dict = new DictionaryValue(); |
+ event_dict->SetInteger(L"type", static_cast<int>(entry.event.type)); |
+ event_dict->SetInteger(L"phase", static_cast<int>(entry.event.phase)); |
+ entry_dict->Set(L"event", event_dict); |
+ } |
+ |
+ // Add the string information (events my have a string too, due to current |
+ // hacks). |
+ if (entry.type == net::NetLog::Entry::TYPE_STRING || !entry.string.empty()) { |
+ entry_dict->SetString(L"string", entry.string); |
+ } |
+ |
+ // Treat string literals the same as strings. |
+ if (entry.type == net::NetLog::Entry::TYPE_STRING_LITERAL) { |
+ entry_dict->SetString(L"string", entry.literal); |
+ } |
+ |
+ if (entry.type == net::NetLog::Entry::TYPE_ERROR_CODE) { |
+ entry_dict->SetInteger(L"error_code", entry.error_code); |
+ } |
+ |
+ CallJavascriptFunction(L"onLogEntryAdded", entry_dict); |
+} |
+ |
void NetInternalsMessageHandler::IOThreadImpl::DispatchToMessageHandler( |
Value* arg, MessageHandler method) { |
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |