summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorasargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-07 16:09:11 +0000
committerasargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-07 16:09:11 +0000
commit82a437356d6461b84e2d79be4f03c033b63d23cf (patch)
tree37301521bdd007b710977e579d33e1cfddb14fd5 /chrome
parent2a80aee736e7c21323d2d72aa6ff4255e5b0f72a (diff)
downloadchromium_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.cc49
-rw-r--r--chrome/browser/extensions/app_notify_channel_setup.h52
-rw-r--r--chrome/browser/extensions/app_notify_channel_setup_unittest.cc78
-rw-r--r--chrome/browser/extensions/extension_tab_helper.cc45
-rw-r--r--chrome/browser/extensions/extension_tab_helper.h23
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_renderer.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/extension_messages.h13
-rw-r--r--chrome/renderer/extensions/chrome_app_bindings.cc75
-rw-r--r--chrome/renderer/extensions/chrome_app_bindings.h6
-rw-r--r--chrome/renderer/extensions/chrome_webstore_bindings.cc63
-rw-r--r--chrome/renderer/extensions/extension_helper.cc23
-rw-r--r--chrome/renderer/extensions/extension_helper.h8
-rw-r--r--chrome/renderer/weak_v8_function_map.cc51
-rw-r--r--chrome/renderer/weak_v8_function_map.h39
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_