diff options
-rw-r--r-- | chrome/browser/browser_resources.grd | 1 | ||||
-rw-r--r-- | chrome/browser/dom_ui/dom_ui_factory.cc | 3 | ||||
-rw-r--r-- | chrome/browser/dom_ui/net_internals_ui.cc | 347 | ||||
-rw-r--r-- | chrome/browser/dom_ui/net_internals_ui.h | 18 | ||||
-rw-r--r-- | chrome/browser/resources/net_internals/index.html | 32 | ||||
-rwxr-xr-x | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/common/url_constants.cc | 2 | ||||
-rw-r--r-- | chrome/common/url_constants.h | 1 |
8 files changed, 406 insertions, 0 deletions
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index 6980e6d..fcf35ba 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd @@ -64,6 +64,7 @@ without changes to the corresponding grd file. tet --> <include name="IDR_NOTIFICATION_ICON_HTML" file="resources\notification_icon.html" type="BINDATA" /> <include name="IDR_NOTIFICATION_2LINE_HTML" file="resources\notification_2line.html" type="BINDATA" /> <include name="IDR_NOTIFICATION_1LINE_HTML" file="resources\notification_1line.html" type="BINDATA" /> + <include name="IDR_NET_INTERNALS_HTML" file="resources\net_internals\index.html" type="BINDATA" /> </includes> </release> </grit> diff --git a/chrome/browser/dom_ui/dom_ui_factory.cc b/chrome/browser/dom_ui/dom_ui_factory.cc index b6de466..b5ef7f02 100644 --- a/chrome/browser/dom_ui/dom_ui_factory.cc +++ b/chrome/browser/dom_ui/dom_ui_factory.cc @@ -12,6 +12,7 @@ #include "chrome/browser/dom_ui/filebrowse_ui.h" #include "chrome/browser/dom_ui/html_dialog_ui.h" #include "chrome/browser/dom_ui/mediaplayer_ui.h" +#include "chrome/browser/dom_ui/net_internals_ui.h" #include "chrome/browser/dom_ui/new_tab_ui.h" #include "chrome/browser/dom_ui/print_ui.h" #include "chrome/browser/extensions/extension_dom_ui.h" @@ -96,6 +97,8 @@ static DOMUIFactoryFunction GetDOMUIFactoryFunction(const GURL& url) { return &NewDOMUI<ExtensionsUI>; if (url.host() == chrome::kChromeUIHistoryHost) return &NewDOMUI<HistoryUI>; + if (url.host() == chrome::kChromeUINetInternalsHost) + return &NewDOMUI<NetInternalsUI>; #if defined(OS_CHROMEOS) if (url.host() == chrome::kChromeUIFileBrowseHost) diff --git a/chrome/browser/dom_ui/net_internals_ui.cc b/chrome/browser/dom_ui/net_internals_ui.cc new file mode 100644 index 0000000..5d7567c --- /dev/null +++ b/chrome/browser/dom_ui/net_internals_ui.cc @@ -0,0 +1,347 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/dom_ui/net_internals_ui.h" + +#include "app/resource_bundle.h" +#include "base/singleton.h" +#include "base/string_piece.h" +#include "base/values.h" +#include "chrome/browser/dom_ui/chrome_url_data_manager.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/common/url_constants.h" + +#include "grit/browser_resources.h" + +namespace { + +class NetInternalsHTMLSource : public ChromeURLDataManager::DataSource { + public: + NetInternalsHTMLSource(); + + // Called when the network layer has requested a resource underneath + // the path we registered. + virtual void StartDataRequest(const std::string& path, + bool is_off_the_record, + int request_id); + virtual std::string GetMimeType(const std::string&) const; + + private: + ~NetInternalsHTMLSource() {} + DISALLOW_COPY_AND_ASSIGN(NetInternalsHTMLSource); +}; + +// This class receives javascript messages from the renderer. +// Note that the DOMUI infrastructure runs on the UI thread, therefore all of +// this class's methods are expected to run on the UI thread. +// +// Since the network code we want to run lives on the IO thread, we proxy +// everything over to NetInternalsMessageHandler::IOThreadImpl, which runs +// on the IO thread. +// +// TODO(eroman): Can we start on the IO thread to begin with? +class NetInternalsMessageHandler + : public DOMMessageHandler, + public base::SupportsWeakPtr<NetInternalsMessageHandler> { + public: + NetInternalsMessageHandler(); + virtual ~NetInternalsMessageHandler(); + + // DOMMessageHandler implementation. + virtual DOMMessageHandler* Attach(DOMUI* dom_ui); + virtual void RegisterMessages(); + + // Executes the javascript function |function_name| in the renderer, passing + // it the argument |value|. + void CallJavascriptFunction(const std::wstring& function_name, + const Value& value); + + private: + class IOThreadImpl; + + // This is the "real" message handler, which lives on the IO thread. + scoped_refptr<IOThreadImpl> proxy_; + + DISALLOW_COPY_AND_ASSIGN(NetInternalsMessageHandler); +}; + +// This class is the "real" message handler. With the exception of being +// allocated and destroyed on the UI thread, its methods are expected to be +// called from the IO thread. +class NetInternalsMessageHandler::IOThreadImpl + : public base::RefCountedThreadSafe< + NetInternalsMessageHandler::IOThreadImpl, + ChromeThread::DeleteOnUIThread> { + public: + // Type for methods that can be used as MessageHandler callbacks. + typedef void (IOThreadImpl::*MessageHandler)(const Value*); + + // 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); + + ~IOThreadImpl(); + + // Creates a callback that will run |method| on the IO thread. + // + // This can be used with DOMUI::RegisterMessageCallback() to bind to a method + // 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(); + + //-------------------------------- + // Javascript message handlers: + //-------------------------------- + + // TODO(eroman): This is temporary! + void OnTestMessage(const Value* value); + + private: + class CallbackHelper; + + // Helper that runs |method| with |arg|, and deletes |arg| on completion. + void DispatchToMessageHandler(Value* arg, MessageHandler method); + + // Helper that executes |function_name| in the attached renderer. + // The function takes ownership of |arg|. + void CallJavascriptFunction(const std::wstring& function_name, + Value* arg); + + private: + // Pointer to the UI-thread message handler. Only access this from + // the UI thread. + base::WeakPtr<NetInternalsMessageHandler> handler_; + friend class base::RefCountedThreadSafe<IOThreadImpl>; +}; + +// Helper class for a DOMUI::MessageCallback which when excuted calls +// instance->*method(value) on the IO thread. +class NetInternalsMessageHandler::IOThreadImpl::CallbackHelper + : public DOMUI::MessageCallback { + public: + CallbackHelper(IOThreadImpl* instance, IOThreadImpl::MessageHandler method) + : instance_(instance), + method_(method) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + } + + virtual void RunWithParams(const Tuple1<const Value*>& params) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + + // We need to make a copy of the value in order to pass it over to the IO + // thread. We will delete this in IOThreadImpl::DispatchMessageHandler(). + Value* value_copy = params.a ? params.a->DeepCopy() : NULL; + + if (!ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(instance_.get(), + &IOThreadImpl::DispatchToMessageHandler, + value_copy, method_))) { + // Failed posting the task, avoid leaking |value_copy|. + delete value_copy; + } + } + + private: + scoped_refptr<IOThreadImpl> instance_; + IOThreadImpl::MessageHandler method_; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// NetInternalsHTMLSource +// +//////////////////////////////////////////////////////////////////////////////// + +NetInternalsHTMLSource::NetInternalsHTMLSource() + : DataSource(chrome::kChromeUINetInternalsHost, MessageLoop::current()) { +} + +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)); + + scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes); + html_bytes->data.resize(html.size()); + std::copy(html.begin(), html.end(), html_bytes->data.begin()); + + SendResponse(request_id, html_bytes); +} + +std::string NetInternalsHTMLSource::GetMimeType(const std::string&) const { + return "text/html"; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// NetInternalsMessageHandler +// +//////////////////////////////////////////////////////////////////////////////// + +NetInternalsMessageHandler::NetInternalsMessageHandler() {} + +NetInternalsMessageHandler::~NetInternalsMessageHandler() { + if (proxy_) { + // Notify the handler on the IO thread that the renderer is gone. + ChromeThread::PostTask(ChromeThread::IO, FROM_HERE, + NewRunnableMethod(proxy_.get(), &IOThreadImpl::Detach)); + } +} + +DOMMessageHandler* NetInternalsMessageHandler::Attach(DOMUI* dom_ui) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + proxy_ = new IOThreadImpl(this->AsWeakPtr()); + + 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)); +} + +void NetInternalsMessageHandler::CallJavascriptFunction( + const std::wstring& function_name, + const Value& value) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + dom_ui_->CallJavascriptFunction(function_name, value); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// NetInternalsMessageHandler::IOThreadImpl +// +//////////////////////////////////////////////////////////////////////////////// + +NetInternalsMessageHandler::IOThreadImpl::IOThreadImpl( + const base::WeakPtr<NetInternalsMessageHandler>& handler) + : handler_(handler) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); +} + +NetInternalsMessageHandler::IOThreadImpl::~IOThreadImpl() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); +} + +DOMUI::MessageCallback* +NetInternalsMessageHandler::IOThreadImpl::CreateCallback( + MessageHandler method) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + 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. +} + +void NetInternalsMessageHandler::IOThreadImpl::OnTestMessage( + const Value* value) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + + // 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); + } + } + + CallJavascriptFunction( + L"log", + Value::CreateStringValue("Browser received testMessage: " + str)); +} + +void NetInternalsMessageHandler::IOThreadImpl::DispatchToMessageHandler( + Value* arg, MessageHandler method) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + (this->*method)(arg); + delete arg; +} + +void NetInternalsMessageHandler::IOThreadImpl::CallJavascriptFunction( + const std::wstring& function_name, + Value* arg) { + if (ChromeThread::CurrentlyOn(ChromeThread::UI)) { + if (handler_) { + // We check |handler_| in case it was deleted on the UI thread earlier + // while we were running on the IO thread. + handler_->CallJavascriptFunction(function_name, *arg); + } + delete arg; + return; + } + + + // Otherwise if we were called from the IO thread, bridge the request over to + // the UI thread. + + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (!ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod( + this, + &IOThreadImpl::CallJavascriptFunction, + function_name, arg))) { + // Failed posting the task, avoid leaking. + delete arg; + } + +} + +} // namespace + + +//////////////////////////////////////////////////////////////////////////////// +// +// NetInternalsUI +// +//////////////////////////////////////////////////////////////////////////////// + +NetInternalsUI::NetInternalsUI(TabContents* contents) : DOMUI(contents) { + AddMessageHandler((new NetInternalsMessageHandler())->Attach(this)); + + NetInternalsHTMLSource* html_source = new NetInternalsHTMLSource(); + + // Set up the chrome://net-internals/ source. + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + Singleton<ChromeURLDataManager>::get(), + &ChromeURLDataManager::AddDataSource, + make_scoped_refptr(html_source))); +} diff --git a/chrome/browser/dom_ui/net_internals_ui.h b/chrome/browser/dom_ui/net_internals_ui.h new file mode 100644 index 0000000..f1c210e --- /dev/null +++ b/chrome/browser/dom_ui/net_internals_ui.h @@ -0,0 +1,18 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_DOM_UI_NET_INTERNALS_UI_H_ +#define CHROME_BROWSER_DOM_UI_NET_INTERNALS_UI_H_ + +#include "chrome/browser/dom_ui/dom_ui.h" + +class NetInternalsUI : public DOMUI { + public: + explicit NetInternalsUI(TabContents* contents); + + private: + DISALLOW_COPY_AND_ASSIGN(NetInternalsUI); +}; + +#endif // CHROME_BROWSER_DOM_UI_NET_INTERNALS_UI_H_ diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html new file mode 100644 index 0000000..7aff02c --- /dev/null +++ b/chrome/browser/resources/net_internals/index.html @@ -0,0 +1,32 @@ +<html> + <head> + <title>Under construction...</title> + <script> + +// TODO(eroman): This is all temporary... + +function sendTestMessageToBrowser() { + log("Sent message to browser"); + chrome.send('testMessage', [String((new Date()).toLocaleTimeString())]); +} + +function log(msg) { + var l = document.getElementById('log'); + l.appendChild(document.createTextNode(msg + "\n")); +} + + </script> + </head> + + + <body> + <p>This is a work in progress. See http://crbug.com/37421 for details.</p> + + <input onclick="sendTestMessageToBrowser()" + value="SendTestMessageToBrowser" + type=button /> + + <pre id=log></pre> + + </body> +</html> diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 15acb1d..be04397 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -837,6 +837,8 @@ 'browser/dom_ui/mediaplayer_ui.h', 'browser/dom_ui/most_visited_handler.cc', 'browser/dom_ui/most_visited_handler.h', + 'browser/dom_ui/net_internals_ui.cc', + 'browser/dom_ui/net_internals_ui.h', 'browser/dom_ui/new_tab_page_sync_handler.cc', 'browser/dom_ui/new_tab_page_sync_handler.h', 'browser/dom_ui/new_tab_ui.cc', diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 156ca96..9d24745 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc @@ -71,6 +71,8 @@ const char kChromeUIHistoryHost[] = "history"; const char kChromeUIFileBrowseHost[] = "filebrowse"; const char kChromeUIMediaplayerHost[] = "mediaplayer"; const char kChromeUIInspectorHost[] = "inspector"; +// TODO(eroman): This value is temporary, while the page is being implemented. +const char kChromeUINetInternalsHost[] = "net2"; const char kChromeUINewTabHost[] = "newtab"; const char kChromeUIThumbnailPath[] = "thumb"; const char kChromeUIThemePath[] = "theme"; diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index ac03c81..665bd66 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h @@ -69,6 +69,7 @@ extern const char kChromeUIHistoryHost[]; extern const char kChromeUIFileBrowseHost[]; extern const char kChromeUIMediaplayerHost[]; extern const char kChromeUIInspectorHost[]; +extern const char kChromeUINetInternalsHost[]; extern const char kChromeUINewTabHost[]; extern const char kChromeUIThumbnailPath[]; extern const char kChromeUIThemePath[]; |