Index: chrome/browser/dom_ui/net_internals_ui.cc |
=================================================================== |
--- chrome/browser/dom_ui/net_internals_ui.cc (revision 0) |
+++ chrome/browser/dom_ui/net_internals_ui.cc (revision 0) |
@@ -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))); |
+} |
Property changes on: chrome\browser\dom_ui\net_internals_ui.cc |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |