summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/chrome_app_api_browsertest.cc174
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc22
-rw-r--r--chrome/browser/extensions/extension_browsertest.h21
-rw-r--r--chrome/browser/extensions/extension_browsertests_misc.cc74
-rw-r--r--chrome/browser/extensions/extension_service.cc7
-rw-r--r--chrome/browser/extensions/extension_service.h2
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc1
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--chrome/renderer/extensions/chrome_app_bindings.cc122
-rw-r--r--chrome/test/data/extensions/get_app_details_for_frame.html27
12 files changed, 352 insertions, 104 deletions
diff --git a/chrome/browser/extensions/chrome_app_api_browsertest.cc b/chrome/browser/extensions/chrome_app_api_browsertest.cc
new file mode 100644
index 0000000..d34de44
--- /dev/null
+++ b/chrome/browser/extensions/chrome_app_api_browsertest.cc
@@ -0,0 +1,174 @@
+// 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 <string>
+
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/scoped_ptr.h"
+#include "base/string_number_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/test/ui_test_utils.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/mock_host_resolver.h"
+
+class ChromeAppAPITest : public ExtensionBrowserTest {
+ private:
+ virtual void SetUpCommandLine(CommandLine* command_line) {
+ ExtensionBrowserTest::SetUpCommandLine(command_line);
+ command_line->AppendSwitchASCII(switches::kAppsCheckoutURL,
+ "http://checkout.com:");
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, IsInstalled) {
+ std::string app_host("app.com");
+ std::string nonapp_host("nonapp.com");
+
+ host_resolver()->AddRule(app_host, "127.0.0.1");
+ host_resolver()->AddRule(nonapp_host, "127.0.0.1");
+ ASSERT_TRUE(test_server()->Start());
+
+ GURL test_file_url(test_server()->GetURL("extensions/test_file.html"));
+ GURL::Replacements replace_host;
+
+ replace_host.SetHostStr(app_host);
+ GURL app_url(test_file_url.ReplaceComponents(replace_host));
+
+ replace_host.SetHostStr(nonapp_host);
+ GURL non_app_url(test_file_url.ReplaceComponents(replace_host));
+
+
+ // Load an app which includes app.com in its extent.
+ const Extension* extension = LoadExtension(
+ test_data_dir_.AppendASCII("app_dot_com_app"));
+ ASSERT_TRUE(extension);
+
+
+ // Test that a non-app page has chrome.app.isInstalled = false.
+ ui_test_utils::NavigateToURL(browser(), non_app_url);
+ std::wstring get_app_is_installed =
+ L"window.domAutomationController.send("
+ L" JSON.stringify(window.chrome.app.isInstalled));";
+ std::string result;
+ ASSERT_TRUE(
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(),
+ L"", get_app_is_installed, &result));
+ EXPECT_EQ("false", result);
+
+ // Test that a non-app page returns null for chrome.app.getDetails().
+ std::wstring get_app_details =
+ L"window.domAutomationController.send("
+ L" JSON.stringify(window.chrome.app.getDetails()));";
+ ASSERT_TRUE(
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(),
+ L"", get_app_details, &result));
+ EXPECT_EQ("null", result);
+
+ // Check that an app page has chrome.app.isInstalled = true.
+ ui_test_utils::NavigateToURL(browser(), app_url);
+ ASSERT_TRUE(
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(),
+ L"", get_app_is_installed, &result));
+ EXPECT_EQ("true", result);
+
+ // Check that an app page returns the correct result for
+ // chrome.app.getDetails().
+ ui_test_utils::NavigateToURL(browser(), app_url);
+ ASSERT_TRUE(
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(),
+ L"", get_app_details, &result));
+ scoped_ptr<DictionaryValue> app_details(
+ static_cast<DictionaryValue*>(
+ base::JSONReader::Read(result, false /* allow trailing comma */)));
+ // extension->manifest_value() does not contain the id.
+ app_details->Remove("id", NULL);
+ EXPECT_TRUE(app_details.get());
+ EXPECT_TRUE(app_details->Equals(extension->manifest_value()));
+
+
+ // Test that trying to set window.chrome.app.isInstalled throws
+ // an exception.
+ ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(),
+ L"",
+ L"window.domAutomationController.send("
+ L" function() {"
+ L" try {"
+ L" window.chrome.app.isInstalled = false;"
+ L" return 'BAD: Should have thrown by now...';"
+ L" } catch (e) {"
+ L" return 'GOOD: Saw expected error.';"
+ L" }"
+ L" }()"
+ L");",
+ &result));
+ EXPECT_EQ("GOOD: Saw expected error.", result);
+}
+
+IN_PROC_BROWSER_TEST_F(ChromeAppAPITest, GetDetailsForFrame) {
+ std::string app_host("app.com");
+ std::string nonapp_host("nonapp.com");
+ std::string checkout_host("checkout.com");
+
+ host_resolver()->AddRule(app_host, "127.0.0.1");
+ host_resolver()->AddRule(nonapp_host, "127.0.0.1");
+ host_resolver()->AddRule(checkout_host, "127.0.0.1");
+ ASSERT_TRUE(test_server()->Start());
+
+ GURL test_file_url(test_server()->GetURL(
+ "files/extensions/get_app_details_for_frame.html"));
+ GURL::Replacements replace_host;
+
+ replace_host.SetHostStr(checkout_host);
+ GURL checkout_url(test_file_url.ReplaceComponents(replace_host));
+
+ replace_host.SetHostStr(app_host);
+ GURL app_url(test_file_url.ReplaceComponents(replace_host));
+
+ // Load an app which includes app.com in its extent.
+ const Extension* extension = LoadExtension(
+ test_data_dir_.AppendASCII("app_dot_com_app"));
+ ASSERT_TRUE(extension);
+
+ // Test that normal pages (even apps) cannot use getDetailsForFrame().
+ ui_test_utils::NavigateToURL(browser(), app_url);
+ std::wstring test_unsuccessful_access =
+ L"window.domAutomationController.send(window.testUnsuccessfulAccess())";
+ bool result = false;
+ ASSERT_TRUE(
+ ui_test_utils::ExecuteJavaScriptAndExtractBool(
+ browser()->GetSelectedTabContents()->render_view_host(),
+ L"", test_unsuccessful_access, &result));
+ EXPECT_TRUE(result);
+
+ // Test that checkout can use getDetailsForFrame() and that it works
+ // correctly.
+ ui_test_utils::NavigateToURL(browser(), checkout_url);
+ std::wstring get_details_for_frame =
+ L"window.domAutomationController.send("
+ L" JSON.stringify(chrome.app.getDetailsForFrame(frames[0])))";
+ std::string json;
+ ASSERT_TRUE(
+ ui_test_utils::ExecuteJavaScriptAndExtractString(
+ browser()->GetSelectedTabContents()->render_view_host(),
+ L"", get_details_for_frame, &json));
+
+ scoped_ptr<DictionaryValue> app_details(
+ static_cast<DictionaryValue*>(
+ base::JSONReader::Read(json, false /* allow trailing comma */)));
+ // extension->manifest_value() does not contain the id.
+ app_details->Remove("id", NULL);
+ EXPECT_TRUE(app_details.get());
+ EXPECT_TRUE(app_details->Equals(extension->manifest_value()));
+}
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index a93ffe2..3f22a38 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -59,9 +59,8 @@ void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
#endif
}
-bool ExtensionBrowserTest::LoadExtensionImpl(const FilePath& path,
- bool incognito_enabled,
- bool fileaccess_enabled) {
+const Extension* ExtensionBrowserTest::LoadExtensionImpl(
+ const FilePath& path, bool incognito_enabled, bool fileaccess_enabled) {
ExtensionService* service = browser()->profile()->GetExtensionService();
{
NotificationRegistrar registrar;
@@ -84,7 +83,7 @@ bool ExtensionBrowserTest::LoadExtensionImpl(const FilePath& path,
}
}
if (!extension)
- return false;
+ return NULL;
// The call to OnExtensionInstalled ensures the other extension prefs
// are set up with the defaults.
@@ -93,22 +92,27 @@ bool ExtensionBrowserTest::LoadExtensionImpl(const FilePath& path,
service->SetIsIncognitoEnabled(extension->id(), incognito_enabled);
service->SetAllowFileAccess(extension, fileaccess_enabled);
- return WaitForExtensionHostsToLoad();
+ if (!WaitForExtensionHostsToLoad())
+ return NULL;
+
+ return extension;
}
-bool ExtensionBrowserTest::LoadExtension(const FilePath& path) {
+const Extension* ExtensionBrowserTest::LoadExtension(const FilePath& path) {
return LoadExtensionImpl(path, false, true);
}
-bool ExtensionBrowserTest::LoadExtensionIncognito(const FilePath& path) {
+const Extension* ExtensionBrowserTest::LoadExtensionIncognito(
+ const FilePath& path) {
return LoadExtensionImpl(path, true, true);
}
-bool ExtensionBrowserTest::LoadExtensionNoFileAccess(const FilePath& path) {
+const Extension* ExtensionBrowserTest::LoadExtensionNoFileAccess(
+ const FilePath& path) {
return LoadExtensionImpl(path, false, false);
}
-bool ExtensionBrowserTest::LoadExtensionIncognitoNoFileAccess(
+const Extension* ExtensionBrowserTest::LoadExtensionIncognitoNoFileAccess(
const FilePath& path) {
return LoadExtensionImpl(path, true, false);
}
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index 2fda271..72ffa0c 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -16,6 +16,8 @@
#include "content/common/notification_observer.h"
#include "content/common/notification_type.h"
+class Extension;
+
// Base class for extension browser tests. Provides utilities for loading,
// unloading, and installing extensions.
class ExtensionBrowserTest
@@ -24,20 +26,20 @@ class ExtensionBrowserTest
ExtensionBrowserTest();
virtual void SetUpCommandLine(CommandLine* command_line);
- bool LoadExtension(const FilePath& path);
+ const Extension* LoadExtension(const FilePath& path);
// Same as above, but enables the extension in incognito mode first.
- bool LoadExtensionIncognito(const FilePath& path);
-
- // Loads extension and imitates that it is a component extension.
- bool LoadExtensionAsComponent(const FilePath& path);
+ const Extension* LoadExtensionIncognito(const FilePath& path);
// By default, unpacked extensions have file access: this loads them with
// that permission removed.
- bool LoadExtensionNoFileAccess(const FilePath& path);
+ const Extension* LoadExtensionNoFileAccess(const FilePath& path);
// Same as above, but enables the extension in incognito mode first.
- bool LoadExtensionIncognitoNoFileAccess(const FilePath& path);
+ const Extension* LoadExtensionIncognitoNoFileAccess(const FilePath& path);
+
+ // Loads extension and imitates that it is a component extension.
+ bool LoadExtensionAsComponent(const FilePath& path);
// Pack the extension in |dir_path| into a crx file and return its path.
// Return an empty FilePath if there were errors.
@@ -142,8 +144,9 @@ class ExtensionBrowserTest
InstallUIType ui_type,
int expected_change,
Profile* profile);
- bool LoadExtensionImpl(const FilePath& path, bool incognito_enabled,
- bool fileaccess_enabled);
+ const Extension* LoadExtensionImpl(const FilePath& path,
+ bool incognito_enabled,
+ bool fileaccess_enabled);
bool WaitForExtensionHostsToLoad();
diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc
index 16f0e80..5800fa3 100644
--- a/chrome/browser/extensions/extension_browsertests_misc.cc
+++ b/chrome/browser/extensions/extension_browsertests_misc.cc
@@ -26,7 +26,6 @@
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/site_instance.h"
#include "content/browser/tab_contents/tab_contents.h"
-#include "net/base/mock_host_resolver.h"
#include "net/base/net_util.h"
#include "net/test/test_server.h"
@@ -831,71 +830,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_OptionsPage) {
tab_strip->GetTabContentsAt(1)->tab_contents()->GetURL());
}
-// Test window.chrome.app.isInstalled .
-IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PropertyAppIsInstalled) {
- std::string app_host("app.com");
- std::string nonapp_host("nonapp.com");
-
- host_resolver()->AddRule(app_host, "127.0.0.1");
- host_resolver()->AddRule(nonapp_host, "127.0.0.1");
- ASSERT_TRUE(test_server()->Start());
-
- GURL test_file_url(test_server()->GetURL("extensions/test_file.html"));
- GURL::Replacements replace_host;
-
- replace_host.SetHostStr(app_host);
- GURL app_url(test_file_url.ReplaceComponents(replace_host));
-
- replace_host.SetHostStr(nonapp_host);
- GURL non_app_url(test_file_url.ReplaceComponents(replace_host));
-
-
- // Load an app which includes app.com in its extent.
- ASSERT_TRUE(LoadExtension(
- test_data_dir_.AppendASCII("app_dot_com_app")));
-
-
- // Test that a non-app page has chrome.app.isInstalled = false.
- ui_test_utils::NavigateToURL(browser(), non_app_url);
- std::wstring get_app_is_installed =
- L"window.domAutomationController.send("
- L" JSON.stringify(window.chrome.app.isInstalled));";
- std::string result;
- ASSERT_TRUE(
- ui_test_utils::ExecuteJavaScriptAndExtractString(
- browser()->GetSelectedTabContents()->render_view_host(),
- L"",
- get_app_is_installed.c_str(),
- &result));
- EXPECT_EQ("false", result);
-
-
- // Check that an app page has chrome.app.isInstalled = true.
- ui_test_utils::NavigateToURL(browser(), app_url);
- ASSERT_TRUE(
- ui_test_utils::ExecuteJavaScriptAndExtractString(
- browser()->GetSelectedTabContents()->render_view_host(),
- L"",
- get_app_is_installed.c_str(),
- &result));
- EXPECT_EQ("true", result);
-
-
- // Test that trying to set window.chrome.app.isInstalled throws
- // an exception.
- ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
- browser()->GetSelectedTabContents()->render_view_host(),
- L"",
- L"window.domAutomationController.send("
- L" function() {"
- L" try {"
- L" window.chrome.app.isInstalled = false;"
- L" return 'BAD: Should have thrown by now...';"
- L" } catch (e) {"
- L" return 'GOOD: Saw expected error.';"
- L" }"
- L" }()"
- L");",
- &result));
- EXPECT_EQ("GOOD: Saw expected error.", result);
-}
+//==============================================================================
+// STOP! Please do not add any more random-ass tests here. Create new files for
+// your tests grouped by functionality. Also, you should strongly consider using
+// ExtensionAPITest if possible.
+//==============================================================================
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index a97bd0d..78c3ff0 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -810,13 +810,13 @@ void ExtensionService::LoadComponentExtensions() {
}
}
-void ExtensionService::LoadComponentExtension(
+const Extension* ExtensionService::LoadComponentExtension(
const ComponentExtensionInfo &info) {
JSONStringValueSerializer serializer(info.manifest);
scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
if (!manifest.get()) {
DLOG(ERROR) << "Failed to parse manifest for extension";
- return;
+ return NULL;
}
int flags = Extension::REQUIRE_KEY;
@@ -831,9 +831,10 @@ void ExtensionService::LoadComponentExtension(
&error));
if (!extension.get()) {
NOTREACHED() << error;
- return;
+ return NULL;
}
AddExtension(extension);
+ return extension;
}
void ExtensionService::LoadAllExtensions() {
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index fb897aa..ee486f7 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -258,7 +258,7 @@ class ExtensionService
void LoadComponentExtensions();
// Loads particular component extension.
- void LoadComponentExtension(const ComponentExtensionInfo& info);
+ const Extension* LoadComponentExtension(const ComponentExtensionInfo& info);
// Loads all known extensions (used by startup and testing code).
void LoadAllExtensions();
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index 8c2664e..cef75c1 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -684,6 +684,7 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer(
switches::kAllowHTTPBackgroundPage,
switches::kAllowScriptingGallery,
switches::kAlwaysAuthorizePlugins,
+ switches::kAppsCheckoutURL,
switches::kAppsGalleryURL,
// We propagate the Chrome Frame command line here as well in case the
// renderer is not run in the sandbox.
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 981d3a8..284b916 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2241,6 +2241,7 @@
'browser/extensions/browser_action_test_util_gtk.cc',
'browser/extensions/browser_action_test_util_mac.mm',
'browser/extensions/browser_action_test_util_views.cc',
+ 'browser/extensions/chrome_app_api_browsertest.cc',
'browser/extensions/content_script_apitest.cc',
'browser/extensions/convert_web_app_browsertest.cc',
'browser/extensions/cross_origin_xhr_apitest.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 44aa7cd..efbb36b 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -47,6 +47,10 @@ const char kApp[] = "app";
// according to its configuration.
const char kAppId[] = "app-id";
+// Override the apps checkout URL, which is used to determine when to expose
+// some private APIs.
+const char kAppsCheckoutURL[] = "apps-checkout-url";
+
// Specifying this flag allows the webstorePrivate APIs to return browser (aka
// sync) login tokens to be used for auto-login in the Web Store (normally they
// do not).
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 640e764..64bc63c 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -32,6 +32,7 @@ extern const char kAlwaysAuthorizePlugins[];
extern const char kAlwaysEnableDevTools[];
extern const char kApp[];
extern const char kAppId[];
+extern const char kAppsCheckoutURL[];
extern const char kAppsGalleryReturnTokens[];
extern const char kAppsGalleryURL[];
extern const char kAppsGalleryUpdateURL[];
diff --git a/chrome/renderer/extensions/chrome_app_bindings.cc b/chrome/renderer/extensions/chrome_app_bindings.cc
index ef072346..e71209d 100644
--- a/chrome/renderer/extensions/chrome_app_bindings.cc
+++ b/chrome/renderer/extensions/chrome_app_bindings.cc
@@ -4,8 +4,13 @@
#include "chrome/renderer/extensions/chrome_app_bindings.h"
+#include "base/command_line.h"
+#include "base/json/json_writer.h"
#include "base/string16.h"
+#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_set.h"
#include "chrome/renderer/extensions/bindings_utils.h"
#include "chrome/renderer/extensions/extension_dispatcher.h"
@@ -15,25 +20,66 @@
using WebKit::WebFrame;
+namespace {
+
+bool IsCheckoutURL(const std::string& url_spec) {
+ std::string checkout_url_prefix =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kAppsCheckoutURL);
+ if (checkout_url_prefix.empty())
+ checkout_url_prefix = "https://checkout.google.com/";
+
+ return StartsWithASCII(url_spec, checkout_url_prefix, false);
+}
+
+bool CheckAccessToAppDetails() {
+ WebFrame* frame = WebFrame::frameForCurrentContext();
+ if (!frame) {
+ LOG(ERROR) << "Could not get frame for current context.";
+ return false;
+ }
+
+ if (!IsCheckoutURL(frame->url().spec())) {
+ std::string error("Access denied for URL: ");
+ error += frame->url().spec();
+ v8::ThrowException(v8::String::New(error.c_str()));
+ return false;
+ }
+
+ return true;
+}
+
+}
+
namespace extensions_v8 {
static const char* const kAppExtensionName = "v8/ChromeApp";
class ChromeAppExtensionWrapper : public v8::Extension {
public:
- explicit ChromeAppExtensionWrapper(ExtensionDispatcher* extension_dispatcher)
- : v8::Extension(kAppExtensionName,
- "var chrome;"
- "if (!chrome)"
- " chrome = {};"
- "if (!chrome.app) {"
- " chrome.app = new function() {"
- " native function GetIsInstalled();"
- " native function Install();"
- " this.__defineGetter__('isInstalled', GetIsInstalled);"
- " this.install = Install;"
- " };"
- "}") {
+ explicit ChromeAppExtensionWrapper(ExtensionDispatcher* extension_dispatcher) :
+ v8::Extension(kAppExtensionName,
+ "var chrome;"
+ "if (!chrome)"
+ " chrome = {};"
+ "if (!chrome.app) {"
+ " chrome.app = new function() {"
+ " native function GetIsInstalled();"
+ " native function Install();"
+ " native function GetDetails();"
+ " native function GetDetailsForFrame();"
+ " this.__defineGetter__('isInstalled', GetIsInstalled);"
+ " this.install = Install;"
+ " this.getDetails = function() {"
+ " var json = GetDetails();"
+ " return json == null ? null : JSON.parse(json);"
+ " };"
+ " this.getDetailsForFrame = function(frame) {"
+ " var json = GetDetailsForFrame(frame);"
+ " return json == null ? null : JSON.parse(json);"
+ " };"
+ " };"
+ "}") {
extension_dispatcher_ = extension_dispatcher;
}
@@ -47,6 +93,10 @@ class ChromeAppExtensionWrapper : public v8::Extension {
return v8::FunctionTemplate::New(GetIsInstalled);
} else if (name->Equals(v8::String::New("Install"))) {
return v8::FunctionTemplate::New(Install);
+ } else if (name->Equals(v8::String::New("GetDetails"))) {
+ return v8::FunctionTemplate::New(GetDetails);
+ } else if (name->Equals(v8::String::New("GetDetailsForFrame"))) {
+ return v8::FunctionTemplate::New(GetDetailsForFrame);
} else {
return v8::Handle<v8::FunctionTemplate>();
}
@@ -80,6 +130,52 @@ class ChromeAppExtensionWrapper : public v8::Extension {
return v8::Undefined();
}
+ static v8::Handle<v8::Value> GetDetails(const v8::Arguments& args) {
+ return GetDetailsForFrameImpl(WebFrame::frameForCurrentContext());
+ }
+
+ static v8::Handle<v8::Value> GetDetailsForFrame(
+ const v8::Arguments& args) {
+ if (!CheckAccessToAppDetails())
+ return v8::Undefined();
+
+ if (args.Length() < 0)
+ return v8::ThrowException(v8::String::New("Not enough arguments."));
+
+ if (!args[0]->IsObject()) {
+ return v8::ThrowException(
+ v8::String::New("Argument 0 must be an object."));
+ }
+
+ v8::Local<v8::Context> context =
+ v8::Local<v8::Object>::Cast(args[0])->CreationContext();
+ CHECK(!context.IsEmpty());
+
+ WebFrame* target_frame = WebFrame::frameForContext(context);
+ if (!target_frame) {
+ return v8::ThrowException(
+ v8::String::New("Could not find frame for specified object."));
+ }
+
+ return GetDetailsForFrameImpl(target_frame);
+ }
+
+ static v8::Handle<v8::Value> GetDetailsForFrameImpl(const WebFrame* frame) {
+ const ::Extension* extension =
+ extension_dispatcher_->extensions()->GetByURL(frame->url());
+ if (!extension)
+ return v8::Null();
+
+ std::string manifest_json;
+ const bool kPrettyPrint = false;
+ scoped_ptr<DictionaryValue> manifest_copy(
+ extension->manifest_value()->DeepCopy());
+ manifest_copy->SetString("id", extension->id());
+ base::JSONWriter::Write(manifest_copy.get(), kPrettyPrint, &manifest_json);
+
+ return v8::String::New(manifest_json.c_str(), manifest_json.size());
+ }
+
static ExtensionDispatcher* extension_dispatcher_;
};
diff --git a/chrome/test/data/extensions/get_app_details_for_frame.html b/chrome/test/data/extensions/get_app_details_for_frame.html
new file mode 100644
index 0000000..81b4f2a
--- /dev/null
+++ b/chrome/test/data/extensions/get_app_details_for_frame.html
@@ -0,0 +1,27 @@
+<script>
+function testUnsuccessfulAccess() {
+ try {
+ chrome.app.getDetailsForFrame(frames[0]);
+ } catch (e) {
+ if (e.indexOf("Access denied") == 0)
+ return true;
+ else
+ throw e;
+ }
+ return false;
+}
+
+function getFrameURL(host) {
+ var result = "http://" + host;
+ if (location.port) {
+ result += ":";
+ result += location.port;
+ }
+ result += location.pathname;
+ return result;
+}
+
+var iframe = document.createElement("iframe");
+iframe.src = getFrameURL("app.com");
+document.documentElement.appendChild(iframe);
+</script>