diff options
author | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-07 16:09:11 +0000 |
---|---|---|
committer | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-07 16:09:11 +0000 |
commit | 82a437356d6461b84e2d79be4f03c033b63d23cf (patch) | |
tree | 37301521bdd007b710977e579d33e1cfddb14fd5 /chrome | |
parent | 2a80aee736e7c21323d2d72aa6ff4255e5b0f72a (diff) | |
download | chromium_src-82a437356d6461b84e2d79be4f03c033b63d23cf.zip chromium_src-82a437356d6461b84e2d79be4f03c033b63d23cf.tar.gz chromium_src-82a437356d6461b84e2d79be4f03c033b63d23cf.tar.bz2 |
Relanding: Add js api for hosted/packaged apps to request notification authorization
(this time with fixed unit test, *and* as a special bonus, fixed compile error)
BUG=98145
TEST=None (more pieces will be landing that will make it testable)
TBR=aa@chromium.org
Original Review URL: http://codereview.chromium.org/8113006
Review URL: http://codereview.chromium.org/8186008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@104493 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/extensions/app_notify_channel_setup.cc | 49 | ||||
-rw-r--r-- | chrome/browser/extensions/app_notify_channel_setup.h | 52 | ||||
-rw-r--r-- | chrome/browser/extensions/app_notify_channel_setup_unittest.cc | 78 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tab_helper.cc | 45 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_tab_helper.h | 23 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_renderer.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/extensions/extension_messages.h | 13 | ||||
-rw-r--r-- | chrome/renderer/extensions/chrome_app_bindings.cc | 75 | ||||
-rw-r--r-- | chrome/renderer/extensions/chrome_app_bindings.h | 6 | ||||
-rw-r--r-- | chrome/renderer/extensions/chrome_webstore_bindings.cc | 63 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_helper.cc | 23 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_helper.h | 8 | ||||
-rw-r--r-- | chrome/renderer/weak_v8_function_map.cc | 51 | ||||
-rw-r--r-- | chrome/renderer/weak_v8_function_map.h | 39 |
16 files changed, 470 insertions, 60 deletions
diff --git a/chrome/browser/extensions/app_notify_channel_setup.cc b/chrome/browser/extensions/app_notify_channel_setup.cc new file mode 100644 index 0000000..8bbe51f --- /dev/null +++ b/chrome/browser/extensions/app_notify_channel_setup.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2011 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/extensions/app_notify_channel_setup.h" + +#include "content/browser/browser_thread.h" + +AppNotifyChannelSetup::AppNotifyChannelSetup( + int request_id, + const std::string& client_id, + const GURL& requestor_url, + base::WeakPtr<AppNotifyChannelSetup::Delegate> delegate) + : request_id_(request_id), + client_id_(client_id), + requestor_url_(requestor_url), + delegate_(delegate) {} + +AppNotifyChannelSetup::~AppNotifyChannelSetup() {} + +void AppNotifyChannelSetup::Start() { + AddRef(); // Balanced in ReportResult. + + + // TODO(asargent) - We will eventually check here whether the user is logged + // in to the browser or not. If they are, we'll make a request to a server + // with the browser login credentials to get a channel id for the app to use + // in server pushed notifications. If they are not logged in, we'll prompt + // for login and if they sign in, then continue as in the first case. + // Otherwise we'll return an error message. + + // For now, just reply with an error of 'not_implemented'. + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + NewRunnableMethod(this, + &AppNotifyChannelSetup::ReportResult, + std::string(), + std::string("not_implemented"))); +} + +void AppNotifyChannelSetup::ReportResult( + const std::string& channel_id, + const std::string& error) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (delegate_.get()) + delegate_->AppNotifyChannelSetupComplete(request_id_, channel_id, error); + Release(); // Matches AddRef in Start. +} diff --git a/chrome/browser/extensions/app_notify_channel_setup.h b/chrome/browser/extensions/app_notify_channel_setup.h new file mode 100644 index 0000000..c44f8f1 --- /dev/null +++ b/chrome/browser/extensions/app_notify_channel_setup.h @@ -0,0 +1,52 @@ +// Copyright (c) 2011 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_EXTENSIONS_APP_NOTIFY_CHANNEL_SETUP_H_ +#define CHROME_BROWSER_EXTENSIONS_APP_NOTIFY_CHANNEL_SETUP_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "googleurl/src/gurl.h" + +// This class uses the browser login credentials to fetch a channel ID for an +// app to use when sending server push notifications. +class AppNotifyChannelSetup + : public base::RefCountedThreadSafe<AppNotifyChannelSetup> { + public: + class Delegate { + public: + // If successful, |channel_id| will be non-empty. On failure, |channel_id| + // will be empty and |error| will contain an error to report to the JS + // callback. + virtual void AppNotifyChannelSetupComplete(int request_id, + const std::string& channel_id, + const std::string& error) = 0; + }; + + AppNotifyChannelSetup(int request_id, + const std::string& client_id, + const GURL& requestor_url, + base::WeakPtr<Delegate> delegate); + + // This begins the process of fetching the channel id using the browser login + // credentials. If the user isn't logged in to chrome, this will first cause a + // prompt to appear asking the user to log in. + void Start(); + + private: + friend class base::RefCountedThreadSafe<AppNotifyChannelSetup>; + + virtual ~AppNotifyChannelSetup(); + + void ReportResult(const std::string& channel_id, const std::string& error); + + int request_id_; + std::string client_id_; + GURL requestor_url_; + base::WeakPtr<Delegate> delegate_; + + DISALLOW_COPY_AND_ASSIGN(AppNotifyChannelSetup); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_APP_NOTIFY_CHANNEL_SETUP_H_ diff --git a/chrome/browser/extensions/app_notify_channel_setup_unittest.cc b/chrome/browser/extensions/app_notify_channel_setup_unittest.cc new file mode 100644 index 0000000..f2eba1b --- /dev/null +++ b/chrome/browser/extensions/app_notify_channel_setup_unittest.cc @@ -0,0 +1,78 @@ +// Copyright (c) 2011 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 "base/compiler_specific.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop.h" +#include "chrome/browser/extensions/app_notify_channel_setup.h" +#include "content/browser/browser_thread.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +class TestDelegate : public AppNotifyChannelSetup::Delegate, + public base::SupportsWeakPtr<TestDelegate> { + public: + TestDelegate() : was_called_(false) {} + virtual ~TestDelegate() {} + + virtual void AppNotifyChannelSetupComplete( + int request_id, + const std::string& channel_id, + const std::string& error) OVERRIDE { + EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI)); + EXPECT_FALSE(was_called_); + was_called_ = true; + request_id_ = request_id; + channel_id_ = channel_id; + error_ = error; + MessageLoop::current()->Quit(); + } + + // Called to check that we were called with the expected arguments. + void ExpectWasCalled(int expected_request_id, + const std::string& expected_channel_id, + const std::string& expected_error) { + EXPECT_TRUE(was_called_); + EXPECT_EQ(expected_request_id, request_id_); + EXPECT_EQ(expected_channel_id, channel_id_); + EXPECT_EQ(expected_error, error_); + } + + private: + // Has our callback been called yet? + bool was_called_; + + // When our AppNotifyChannelSetupComplete method is called, we copy the + // arguments into these member variables. + int request_id_; + std::string channel_id_; + std::string error_; + + DISALLOW_COPY_AND_ASSIGN(TestDelegate); +}; + +} // namespace + + +TEST(AppNotifyChannelSetupTest, WasDelegateCalled) { + MessageLoop message_loop; + BrowserThread thread(BrowserThread::UI, &message_loop); + + TestDelegate delegate; + int request_id = 5; + std::string client_id = "12345"; + GURL url("http://www.google.com"); + + scoped_refptr<AppNotifyChannelSetup > setup = + new AppNotifyChannelSetup(request_id, + client_id, + url, + delegate.AsWeakPtr()); + setup->Start(); + MessageLoop::current()->Run(); + delegate.ExpectWasCalled( + request_id, std::string(), std::string("not_implemented")); +} diff --git a/chrome/browser/extensions/extension_tab_helper.cc b/chrome/browser/extensions/extension_tab_helper.cc index df7209c..0d91f82 100644 --- a/chrome/browser/extensions/extension_tab_helper.cc +++ b/chrome/browser/extensions/extension_tab_helper.cc @@ -18,6 +18,7 @@ #include "chrome/common/extensions/extension_icon_set.h" #include "chrome/common/extensions/extension_messages.h" #include "chrome/common/extensions/extension_resource.h" +#include "content/browser/renderer_host/render_view_host.h" #include "content/browser/renderer_host/render_widget_host_view.h" #include "content/browser/tab_contents/navigation_details.h" #include "content/browser/tab_contents/tab_contents.h" @@ -127,6 +128,8 @@ bool ExtensionTabHelper::OnMessageReceived(const IPC::Message& message) { OnInstallApplication) IPC_MESSAGE_HANDLER(ExtensionHostMsg_InlineWebstoreInstall, OnInlineWebstoreInstall) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppNotifyChannel, + OnGetAppNotifyChannel) IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -155,6 +158,48 @@ void ExtensionTabHelper::OnInlineWebstoreInstall( installer->BeginInstall(); } +void ExtensionTabHelper::OnGetAppNotifyChannel( + int request_id, + const GURL& requestor_url, + const std::string& client_id) { + + // Check for permission first. + Profile* profile = + Profile::FromBrowserContext(tab_contents()->browser_context()); + ExtensionService* extension_service = profile->GetExtensionService(); + ExtensionProcessManager* process_manager = + profile->GetExtensionProcessManager(); + RenderProcessHost* process = + tab_contents_wrapper()->render_view_host()->process(); + const Extension* extension = + extension_service->GetInstalledApp(requestor_url); + bool allowed = + extension && + extension->is_app() && + extension->HasAPIPermission( + ExtensionAPIPermission::kExperimental) && + (extension->is_hosted_app() || + process_manager->GetExtensionProcess(requestor_url) == process); + if (!allowed) { + AppNotifyChannelSetupComplete(request_id, "", "permission_error"); + return; + } + + scoped_refptr<AppNotifyChannelSetup> channel_setup( + new AppNotifyChannelSetup(request_id, + client_id, + requestor_url, + this->AsWeakPtr())); + channel_setup->Start(); + // We'll get called back in AppNotifyChannelSetupComplete. +} + +void ExtensionTabHelper::AppNotifyChannelSetupComplete( + int request_id, const std::string& client_id, const std::string& error) { + Send(new ExtensionMsg_GetAppNotifyChannelResponse( + routing_id(), request_id, client_id, error)); +} + void ExtensionTabHelper::OnRequest( const ExtensionHostMsg_Request_Params& request) { extension_function_dispatcher_.Dispatch(request, diff --git a/chrome/browser/extensions/extension_tab_helper.h b/chrome/browser/extensions/extension_tab_helper.h index 7dda6ff..9e77970 100644 --- a/chrome/browser/extensions/extension_tab_helper.h +++ b/chrome/browser/extensions/extension_tab_helper.h @@ -6,11 +6,13 @@ #define CHROME_BROWSER_EXTENSIONS_EXTENSION_TAB_HELPER_H_ #pragma once -#include "content/browser/tab_contents/tab_contents_observer.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/extensions/app_notify_channel_setup.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/image_loading_tracker.h" #include "chrome/browser/extensions/webstore_inline_installer.h" #include "chrome/common/web_apps.h" +#include "content/browser/tab_contents/tab_contents_observer.h" #include "third_party/skia/include/core/SkBitmap.h" class Extension; @@ -22,10 +24,13 @@ struct LoadCommittedDetails; } // Per-tab extension helper. Also handles non-extension apps. -class ExtensionTabHelper : public TabContentsObserver, - public ExtensionFunctionDispatcher::Delegate, - public ImageLoadingTracker::Observer, - public WebstoreInlineInstaller::Delegate { +class ExtensionTabHelper + : public TabContentsObserver, + public ExtensionFunctionDispatcher::Delegate, + public ImageLoadingTracker::Observer, + public WebstoreInlineInstaller::Delegate, + public AppNotifyChannelSetup::Delegate, + public base::SupportsWeakPtr<ExtensionTabHelper> { public: explicit ExtensionTabHelper(TabContentsWrapper* wrapper); virtual ~ExtensionTabHelper(); @@ -100,6 +105,9 @@ class ExtensionTabHelper : public TabContentsObserver, void OnInlineWebstoreInstall(int install_id, const std::string& webstore_item_id, const GURL& requestor_url); + void OnGetAppNotifyChannel(int request_id, + const GURL& requestor_url, + const std::string& client_id); void OnRequest(const ExtensionHostMsg_Request_Params& params); // App extensions related methods: @@ -117,6 +125,11 @@ class ExtensionTabHelper : public TabContentsObserver, virtual void OnInlineInstallFailure(int install_id, const std::string& error) OVERRIDE; + // AppNotifyChannelSetup::Delegate. + virtual void AppNotifyChannelSetupComplete(int request_id, + const std::string& channel_id, + const std::string& error); + // Data for app extensions --------------------------------------------------- // If non-null this tab is an app tab and this is the extension the tab was diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 69a9d7d..e7b0141 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -904,6 +904,8 @@ 'browser/extensions/app_notification.h', 'browser/extensions/app_notification_manager.cc', 'browser/extensions/app_notification_manager.h', + 'browser/extensions/app_notify_channel_setup.cc', + 'browser/extensions/app_notify_channel_setup.h', 'browser/extensions/app_notification_storage.cc', 'browser/extensions/app_notification_storage.h', 'browser/extensions/apps_promo.cc', diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index 7fdf621..9d6bc84 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -180,6 +180,8 @@ 'renderer/translate_helper.h', 'renderer/visitedlink_slave.cc', 'renderer/visitedlink_slave.h', + 'renderer/weak_v8_function_map.cc', + 'renderer/weak_v8_function_map.h', ], 'conditions': [ ['disable_nacl!=1', { diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index fe03193..33d90e1 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1268,6 +1268,7 @@ 'browser/extensions/app_notification_manager_unittest.cc', 'browser/extensions/app_notification_storage_unittest.cc', 'browser/extensions/app_notification_test_util.cc', + 'browser/extensions/app_notify_channel_setup_unittest.cc', 'browser/extensions/apps_promo_unittest.cc', 'browser/extensions/convert_user_script_unittest.cc', 'browser/extensions/convert_web_app_unittest.cc', diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h index cb22831..9a5da31 100644 --- a/chrome/common/extensions/extension_messages.h +++ b/chrome/common/extensions/extension_messages.h @@ -324,6 +324,19 @@ IPC_MESSAGE_ROUTED3(ExtensionMsg_InlineWebstoreInstallResponse, bool /* whether the install was successful */, std::string /* error */) +// Sent by the renderer when an App is requesting permission to send server +// pushed notifications. +IPC_MESSAGE_ROUTED3(ExtensionHostMsg_GetAppNotifyChannel, + int32 /* request_id */, + GURL /* requestor_url */, + std::string /* client_id */) + +// Response to the renderer for the above message. +IPC_MESSAGE_ROUTED3(ExtensionMsg_GetAppNotifyChannelResponse, + int32 /* request_id */, + std::string /* channel_id */, + std::string /* error */) + // Deliver a message sent with ExtensionHostMsg_PostMessage. IPC_MESSAGE_ROUTED2(ExtensionMsg_DeliverMessage, int /* target_port_id */, diff --git a/chrome/renderer/extensions/chrome_app_bindings.cc b/chrome/renderer/extensions/chrome_app_bindings.cc index c13e497..db0fb36 100644 --- a/chrome/renderer/extensions/chrome_app_bindings.cc +++ b/chrome/renderer/extensions/chrome_app_bindings.cc @@ -14,6 +14,7 @@ #include "chrome/common/extensions/extension_set.h" #include "chrome/renderer/extensions/extension_dispatcher.h" #include "chrome/renderer/extensions/extension_helper.h" +#include "chrome/renderer/weak_v8_function_map.h" #include "content/public/renderer/v8_value_converter.h" #include "content/renderer/render_view.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" @@ -52,6 +53,14 @@ bool CheckAccessToAppDetails() { return true; } +int g_next_request_id = 0; +base::LazyInstance<WeakV8FunctionMap> g_callbacks(base::LINKER_INITIALIZED); + +const char* kMissingClientIdError = "Missing clientId parameter"; +const char* kInvalidClientIdError = "Invalid clientId"; +const char* kCallbackNotAFunctionError = + "The callback that was passed is not a function"; + } // namespace const char kAppExtensionName[] = "v8/ChromeApp"; @@ -72,10 +81,14 @@ class ChromeAppExtensionWrapper : public v8::Extension { " native function Install();" " native function GetDetails();" " native function GetDetailsForFrame();" + " native function GetAppNotifyChannel();" " this.__defineGetter__('isInstalled', GetIsInstalled);" " this.install = Install;" " this.getDetails = GetDetails;" " this.getDetailsForFrame = GetDetailsForFrame;" + " this.experimental = {};" + " this.experimental.getNotificationChannel =" + " GetAppNotifyChannel;" " };" "}") { extension_dispatcher_ = extension_dispatcher; @@ -95,6 +108,8 @@ class ChromeAppExtensionWrapper : public v8::Extension { return v8::FunctionTemplate::New(GetDetails); } else if (name->Equals(v8::String::New("GetDetailsForFrame"))) { return v8::FunctionTemplate::New(GetDetailsForFrame); + } else if (name->Equals(v8::String::New("GetAppNotifyChannel"))) { + return v8::FunctionTemplate::New(GetAppNotifyChannel); } else { return v8::Handle<v8::FunctionTemplate>(); } @@ -180,6 +195,53 @@ class ChromeAppExtensionWrapper : public v8::Extension { frame->mainWorldScriptContext()); } + static v8::Handle<v8::Value> GetAppNotifyChannel(const v8::Arguments& args) { + WebFrame* frame = WebFrame::frameForCurrentContext(); + if (!frame || !frame->view()) + return v8::Undefined(); + + RenderView* render_view = RenderView::FromWebView(frame->view()); + if (!render_view) + return v8::Undefined(); + + if (g_next_request_id < 0) + return v8::Undefined(); + int request_id = g_next_request_id++; + + // Read the required 'clientId' value out of the object at args[0]. + std::string client_id; + if (args.Length() < 1 || !args[0]->IsObject()) { + v8::ThrowException(v8::String::New(kMissingClientIdError)); + return v8::Undefined(); + } + v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(args[0]); + v8::Local<v8::String> client_id_key = v8::String::New("clientId"); + if (obj->Has(client_id_key)) { + v8::String::Utf8Value id_value(obj->Get(client_id_key)); + if (id_value.length() > 0) + client_id = std::string(*id_value); + } + if (client_id.empty()) { + v8::ThrowException(v8::String::New(kInvalidClientIdError)); + return v8::Undefined(); + } + + // Hang on to the callback if there was one. + if (args.Length() >= 2) { + if (args[1]->IsFunction()) { + g_callbacks.Get().Add(request_id, v8::Function::Cast(*args[1])); + } else { + v8::ThrowException(v8::String::New(kCallbackNotAFunctionError)); + return v8::Undefined(); + } + } + + ExtensionHelper* helper = ExtensionHelper::Get(render_view); + helper->GetAppNotifyChannel( + request_id, frame->document().url(), client_id); + return v8::Undefined(); + } + static ExtensionDispatcher* extension_dispatcher_; }; @@ -190,4 +252,17 @@ v8::Extension* ChromeAppExtension::Get( return new ChromeAppExtensionWrapper(extension_dispatcher); } +void ChromeAppExtension::HandleGetAppNotifyChannelResponse( + int request_id, const std::string& channel_id, const std::string& error) { + v8::Persistent<v8::Function> function = g_callbacks.Get().Remove(request_id); + if (function.IsEmpty()) + return; + v8::HandleScope handle_scope; + v8::Context::Scope context_scope(function->CreationContext()); + v8::Handle<v8::Value> argv[2]; + argv[0] = v8::String::New(channel_id.c_str()); + argv[1] = v8::String::New(error.c_str()); + function->Call(v8::Object::New(), arraysize(argv), argv); +} + } // namespace extensions_v8 diff --git a/chrome/renderer/extensions/chrome_app_bindings.h b/chrome/renderer/extensions/chrome_app_bindings.h index 8e7da1b..c02366f3 100644 --- a/chrome/renderer/extensions/chrome_app_bindings.h +++ b/chrome/renderer/extensions/chrome_app_bindings.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -12,6 +12,8 @@ #define CHROME_RENDERER_EXTENSIONS_CHROME_APP_BINDINGS_H_ #pragma once +#include <string> + class ExtensionDispatcher; namespace v8 { @@ -23,6 +25,8 @@ namespace extensions_v8 { class ChromeAppExtension { public: static v8::Extension* Get(ExtensionDispatcher* extension_dispatcher); + static void HandleGetAppNotifyChannelResponse( + int request_id, const std::string& channel_id, const std::string& error); }; } // namespace extensions_v8 diff --git a/chrome/renderer/extensions/chrome_webstore_bindings.cc b/chrome/renderer/extensions/chrome_webstore_bindings.cc index 74e3f95..56bb4b9 100644 --- a/chrome/renderer/extensions/chrome_webstore_bindings.cc +++ b/chrome/renderer/extensions/chrome_webstore_bindings.cc @@ -8,6 +8,7 @@ #include "base/string_util.h" #include "chrome/common/extensions/extension.h" #include "chrome/renderer/extensions/extension_helper.h" +#include "chrome/renderer/weak_v8_function_map.h" #include "content/renderer/render_view.h" #include "googleurl/src/gurl.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" @@ -49,48 +50,10 @@ const char kInvalidWebstoreItemUrlError[] = // (successful or not) via HandleInstallResponse. int g_next_install_id = 0; -// Callbacks are kept track of in maps keyed by install ID. Values are weak -// references to functions. Entries are automatically removed when functions -// get garbage collected. -typedef std::map<int, v8::Persistent<v8::Function> > CallbackMap; - -base::LazyInstance<CallbackMap> g_success_callbacks(base::LINKER_INITIALIZED); -base::LazyInstance<CallbackMap> g_failure_callbacks(base::LINKER_INITIALIZED); - -// Extra data to be passed to MakeWeak/RemoveFromCallbackMap to know which entry -// to remove from which map. -struct CallbackMapData { - CallbackMap* callback_map; - int install_id; -}; - -// Disposes of a callback function and its corresponding entry in the callback -// map. -static void RemoveFromCallbackMap(v8::Persistent<v8::Value> context, - void* data) { - CallbackMapData* callback_map_data = static_cast<CallbackMapData*>(data); - callback_map_data->callback_map->erase(callback_map_data->install_id); - delete callback_map_data; - context.Dispose(); -} - -// Adds |callback_param| (assumed to be a function) to |callback_map| under the -// |install_id| key. Will be removed from the map when the value is about to be -// GCed. -static void AddToCallbackMap(int install_id, - v8::Local<v8::Value> callback_param, - CallbackMap* callback_map) { - CHECK(callback_param->IsFunction()); - CallbackMapData* callback_map_data = new CallbackMapData(); - callback_map_data->install_id = install_id; - callback_map_data->callback_map = callback_map; - - v8::Local<v8::Function> function = v8::Function::Cast(*callback_param); - v8::Persistent<v8::Function> wrapper = - v8::Persistent<v8::Function>::New(function); - (*callback_map)[install_id] = wrapper; - wrapper.MakeWeak(callback_map_data, RemoveFromCallbackMap); -} +base::LazyInstance<WeakV8FunctionMap> g_success_callbacks( + base::LINKER_INITIALIZED); +base::LazyInstance<WeakV8FunctionMap> g_failure_callbacks( + base::LINKER_INITIALIZED); } // anonymous namespace @@ -147,7 +110,7 @@ class ExtensionImpl : public v8::Extension { int install_id = g_next_install_id++; if (args.Length() >= 2 && !args[1]->IsUndefined()) { if (args[1]->IsFunction()) { - AddToCallbackMap(install_id, args[1], g_success_callbacks.Pointer()); + g_success_callbacks.Get().Add(install_id, v8::Function::Cast(*args[1])); } else { v8::ThrowException(v8::String::New(kSuccessCallbackNotAFunctionError)); return v8::Undefined(); @@ -155,7 +118,7 @@ class ExtensionImpl : public v8::Extension { } if (args.Length() >= 3 && !args[2]->IsUndefined()) { if (args[2]->IsFunction()) { - AddToCallbackMap(install_id, args[2], g_failure_callbacks.Pointer()); + g_failure_callbacks.Get().Add(install_id, v8::Function::Cast(*args[2])); } else { v8::ThrowException(v8::String::New(kFailureCallbackNotAFunctionError)); return v8::Undefined(); @@ -270,18 +233,16 @@ v8::Extension* ChromeWebstoreExtension::Get() { void ChromeWebstoreExtension::HandleInstallResponse(int install_id, bool success, const std::string& error) { - CallbackMap* callback_map = - success ? g_success_callbacks.Pointer() : g_failure_callbacks.Pointer(); - CallbackMap::iterator iter = callback_map->find(install_id); + WeakV8FunctionMap& callback_map = + success ? g_success_callbacks.Get() : g_failure_callbacks.Get(); - if (iter == callback_map->end() || iter->second.IsEmpty()) return; - const v8::Persistent<v8::Function>& function = (*iter).second; + v8::Persistent<v8::Function> function = callback_map.Remove(install_id); + if (function.IsEmpty()) + return; v8::HandleScope handle_scope; v8::Context::Scope context_scope(function->CreationContext()); v8::Handle<v8::Value> argv[1]; argv[0] = v8::String::New(error.c_str()); function->Call(v8::Object::New(), arraysize(argv), argv); - - callback_map->erase(iter); } diff --git a/chrome/renderer/extensions/extension_helper.cc b/chrome/renderer/extensions/extension_helper.cc index 85f610b..c2c880c 100644 --- a/chrome/renderer/extensions/extension_helper.cc +++ b/chrome/renderer/extensions/extension_helper.cc @@ -9,10 +9,11 @@ #include "base/message_loop.h" #include "base/utf_string_conversions.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/chrome_view_types.h" #include "chrome/common/extensions/extension_messages.h" #include "chrome/common/render_messages.h" #include "chrome/common/url_constants.h" -#include "chrome/common/chrome_view_types.h" +#include "chrome/renderer/extensions/chrome_app_bindings.h" #include "chrome/renderer/extensions/chrome_v8_context.h" #include "chrome/renderer/extensions/chrome_webstore_bindings.h" #include "chrome/renderer/extensions/event_bindings.h" @@ -23,13 +24,14 @@ #include "chrome/renderer/extensions/user_script_slave.h" #include "content/common/json_value_serializer.h" #include "content/renderer/render_view.h" -#include "webkit/glue/image_resource_fetcher.h" -#include "webkit/glue/resource_fetcher.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +#include "webkit/glue/image_resource_fetcher.h" +#include "webkit/glue/resource_fetcher.h" +using extensions_v8::ChromeAppExtension; using WebKit::WebConsoleMessage; using WebKit::WebDataSource; using WebKit::WebFrame; @@ -119,6 +121,19 @@ void ExtensionHelper::OnInlineWebstoreInstallResponse( ChromeWebstoreExtension::HandleInstallResponse(install_id, success, error); } +void ExtensionHelper::GetAppNotifyChannel(int request_id, + const GURL& requestor_url, + const std::string& client_id) { + Send(new ExtensionHostMsg_GetAppNotifyChannel( + routing_id(), request_id, requestor_url, client_id)); +} + +void ExtensionHelper::OnGetAppNotifyChannelResponse( + int request_id, const std::string& channel_id, const std::string& error) { + ChromeAppExtension::HandleGetAppNotifyChannelResponse( + request_id, channel_id, error); +} + bool ExtensionHelper::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(ExtensionHelper, message) @@ -133,6 +148,8 @@ bool ExtensionHelper::OnMessageReceived(const IPC::Message& message) { OnNotifyRendererViewType) IPC_MESSAGE_HANDLER(ExtensionMsg_InlineWebstoreInstallResponse, OnInlineWebstoreInstallResponse) + IPC_MESSAGE_HANDLER(ExtensionMsg_GetAppNotifyChannelResponse, + OnGetAppNotifyChannelResponse) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; diff --git a/chrome/renderer/extensions/extension_helper.h b/chrome/renderer/extensions/extension_helper.h index ef7f4ae..1086a31 100644 --- a/chrome/renderer/extensions/extension_helper.h +++ b/chrome/renderer/extensions/extension_helper.h @@ -46,6 +46,12 @@ class ExtensionHelper std::string webstore_item_id, GURL requestor_url); + // Starts fetching a channel id for server pushed notifications. The result + // comes back via OnGetAppNotifyChannelResponse. + void GetAppNotifyChannel(int request_id, + const GURL& requestor_url, + const std::string& client_id); + int browser_window_id() const { return browser_window_id_; } content::ViewType::Type view_type() const { return view_type_; } @@ -75,6 +81,8 @@ class ExtensionHelper void OnUpdateBrowserWindowId(int window_id); void OnInlineWebstoreInstallResponse( int install_id, bool success, const std::string& error); + void OnGetAppNotifyChannelResponse( + int request_id, const std::string& channel_id, const std::string& error); // Callback triggered when we finish downloading the application definition // file. diff --git a/chrome/renderer/weak_v8_function_map.cc b/chrome/renderer/weak_v8_function_map.cc new file mode 100644 index 0000000..0d70523 --- /dev/null +++ b/chrome/renderer/weak_v8_function_map.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2011 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 "base/logging.h" +#include "chrome/renderer/weak_v8_function_map.h" + +// Extra data to be passed to MakeWeak/RemoveFromMap to know which entry +// to remove from which map. +struct WeakV8FunctionMapData { + base::WeakPtr<WeakV8FunctionMap> map; + int key; +}; + +// Disposes of a callback function and its corresponding entry in the callback +// map, if that callback map is still alive. +static void RemoveFromMap(v8::Persistent<v8::Value> context, + void* data) { + WeakV8FunctionMapData* map_data = + static_cast<WeakV8FunctionMapData*>(data); + if (map_data->map) + map_data->map->Remove(map_data->key); + delete map_data; + context.Dispose(); +} + +WeakV8FunctionMap::WeakV8FunctionMap() + : ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {} + +WeakV8FunctionMap::~WeakV8FunctionMap() {} + + +void WeakV8FunctionMap::Add(int key, + v8::Local<v8::Function> callback_function) { + WeakV8FunctionMapData* map_data = new WeakV8FunctionMapData(); + map_data->key = key; + map_data->map = weak_ptr_factory_.GetWeakPtr(); + v8::Persistent<v8::Function> wrapper = + v8::Persistent<v8::Function>::New(callback_function); + map_[key] = wrapper; + wrapper.MakeWeak(map_data, RemoveFromMap); +} + +v8::Persistent<v8::Function> WeakV8FunctionMap::Remove(int key) { + WeakV8FunctionMap::Map::iterator i = map_.find(key); + if (i == map_.end()) + return v8::Persistent<v8::Function>(); + v8::Persistent<v8::Function> callback = i->second; + map_.erase(i); + return callback; +} diff --git a/chrome/renderer/weak_v8_function_map.h b/chrome/renderer/weak_v8_function_map.h new file mode 100644 index 0000000..a51dc9d --- /dev/null +++ b/chrome/renderer/weak_v8_function_map.h @@ -0,0 +1,39 @@ +// Copyright (c) 2011 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_RENDERER_WEAK_V8_FUNCTION_MAP_H_ +#define CHROME_RENDERER_WEAK_V8_FUNCTION_MAP_H_ +#pragma once + +#include <map> + +#include "base/compiler_specific.h" +#include "base/memory/weak_ptr.h" +#include "v8/include/v8.h" + +// This class lets you keep a mapping of integer to weak reference to a v8 +// function. The entry will automatically get removed from the map if the +// function gets garbage collected. +class WeakV8FunctionMap { + public: + WeakV8FunctionMap(); + ~WeakV8FunctionMap(); + + // Adds |callback_function| to the map under |key|. The entry will be removed + // from the map when the function is about to be GCed. + void Add(int key, v8::Local<v8::Function> callback_function); + + // Removes and returns a entry from the map for |key|. If there was no entry + // for |key|, the return value will return true for IsEmpty(). + v8::Persistent<v8::Function> Remove(int key); + + private: + typedef std::map<int, v8::Persistent<v8::Function> > Map; + Map map_; + base::WeakPtrFactory<WeakV8FunctionMap> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(WeakV8FunctionMap); +}; + +#endif // CHROME_RENDERER_WEAK_V8_FUNCTION_MAP_H_ |