summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome_frame/chrome_frame_activex.cc23
-rw-r--r--chrome_frame/chrome_frame_activex.h5
-rw-r--r--chrome_frame/chrome_frame_activex_base.h72
-rw-r--r--chrome_frame/chrome_frame_automation.cc87
-rw-r--r--chrome_frame/chrome_frame_automation.h9
-rw-r--r--chrome_frame/chrome_frame_delegate.h9
-rw-r--r--chrome_frame/chrome_frame_npapi.cc85
-rw-r--r--chrome_frame/chrome_frame_npapi.h10
-rw-r--r--chrome_frame/chrome_launcher.cc1
-rw-r--r--chrome_frame/chrome_launcher_unittest.cc97
-rw-r--r--chrome_frame/chrome_tab.idl17
-rw-r--r--chrome_frame/test/data/privileged_apis_host.html50
12 files changed, 402 insertions, 63 deletions
diff --git a/chrome_frame/chrome_frame_activex.cc b/chrome_frame/chrome_frame_activex.cc
index 9999fb7..78b09fa 100644
--- a/chrome_frame/chrome_frame_activex.cc
+++ b/chrome_frame/chrome_frame_activex.cc
@@ -43,6 +43,7 @@ ChromeFrameActivex::~ChromeFrameActivex() {
DCHECK(onloaderror_.size() == 0);
DCHECK(onload_.size() == 0);
DCHECK(onreadystatechanged_.size() == 0);
+ DCHECK(onextensionready_.size() == 0);
}
LRESULT ChromeFrameActivex::OnCreate(UINT message, WPARAM wparam, LPARAM lparam,
@@ -147,6 +148,14 @@ void ChromeFrameActivex::OnAutomationServerLaunchFailed(
}
}
+void ChromeFrameActivex::OnExtensionInstalled(
+ const FilePath& path,
+ void* user_data,
+ AutomationMsg_ExtensionResponseValues response) {
+ ScopedBstr path_str(path.value().c_str());
+ Fire_onextensionready(path_str, response);
+}
+
HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
const std::string& param) {
ScopedVariant script_arg(UTF8ToWide(param.c_str()).c_str());
@@ -155,12 +164,23 @@ HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
VARIANT* param) {
+ return InvokeScriptFunction(script_object, param, 1);
+}
+
+HRESULT ChromeFrameActivex::InvokeScriptFunction(const VARIANT& script_object,
+ VARIANT* params,
+ int param_count) {
+ DCHECK(param_count >= 0);
+ DCHECK(params);
+
if (V_VT(&script_object) != VT_DISPATCH) {
return S_FALSE;
}
CComPtr<IDispatch> script(script_object.pdispVal);
- HRESULT hr = script.Invoke1(static_cast<DISPID>(DISPID_VALUE), param);
+ HRESULT hr = script.InvokeN(static_cast<DISPID>(DISPID_VALUE),
+ params,
+ param_count);
// 0x80020101 == SCRIPT_E_REPORTED.
// When the script we're invoking has an error, we get this error back.
DLOG_IF(ERROR, FAILED(hr) && hr != 0x80020101) << "Failed to invoke script";
@@ -276,6 +296,7 @@ HRESULT ChromeFrameActivex::IOleObject_SetClientSite(
&onloaderror_,
&onload_,
&onreadystatechanged_,
+ &onextensionready_,
};
for (int i = 0; i < arraysize(handlers); ++i)
diff --git a/chrome_frame/chrome_frame_activex.h b/chrome_frame/chrome_frame_activex.h
index d60b14b..04169af 100644
--- a/chrome_frame/chrome_frame_activex.h
+++ b/chrome_frame/chrome_frame_activex.h
@@ -95,10 +95,15 @@ END_MSG_MAP()
virtual void ChromeFrameActivex::OnAutomationServerLaunchFailed(
AutomationLaunchResult reason, const std::string& server_version);
virtual void OnLoadFailed(int error_code, const std::string& url);
+ virtual void OnExtensionInstalled(const FilePath& path,
+ void* user_data, AutomationMsg_ExtensionResponseValues response);
// Helper function to execute a function on a script IDispatch interface.
HRESULT InvokeScriptFunction(const VARIANT& script, const std::string& param);
HRESULT InvokeScriptFunction(const VARIANT& script, VARIANT* param);
+ HRESULT InvokeScriptFunction(const VARIANT& script,
+ VARIANT* param,
+ int param_count);
HRESULT GetContainingDocument(IHTMLDocument2** doc);
HRESULT GetDocumentWindow(IHTMLWindow2** window);
diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h
index b8106aa..651ecbf 100644
--- a/chrome_frame/chrome_frame_activex_base.h
+++ b/chrome_frame/chrome_frame_activex_base.h
@@ -115,6 +115,18 @@ class ATL_NO_VTABLE ProxyDIChromeFrameEvents
args,
arraysize(args));
}
+
+ void Fire_onextensionready(BSTR path, long response) {
+ // Arguments in reverse order to the function declaration, because
+ // that's what DISPPARAMS requires.
+ VARIANT args[2] = { { VT_I4, }, { VT_BSTR, } };
+ args[0].lVal = response;
+ args[1].bstrVal = path;
+
+ FireMethodWithParams(CF_EVENT_DISPID_ONEXTENSIONREADY,
+ args,
+ arraysize(args));
+ }
};
extern bool g_first_launch_by_process_;
@@ -749,12 +761,53 @@ END_MSG_MAP()
return S_OK;
}
+ STDMETHOD(installExtension)(BSTR crx_path) {
+ DCHECK(automation_client_.get());
+
+ if (NULL == crx_path) {
+ NOTREACHED();
+ return E_INVALIDARG;
+ }
+
+ if (!is_privileged_) {
+ DLOG(ERROR) << "Attempt to installExtension in non-privileged mode";
+ return E_ACCESSDENIED;
+ }
+
+ FilePath::StringType crx_path_str(crx_path);
+ FilePath crx_file_path(crx_path_str);
+
+ automation_client_->InstallExtension(crx_file_path, NULL);
+ return S_OK;
+ }
+
+ STDMETHOD(loadExtension)(BSTR path) {
+ DCHECK(automation_client_.get());
+
+ if (NULL == path) {
+ NOTREACHED();
+ return E_INVALIDARG;
+ }
+
+ if (!is_privileged_) {
+ DLOG(ERROR) << "Attempt to loadExtension in non-privileged mode";
+ return E_ACCESSDENIED;
+ }
+
+ FilePath::StringType path_str(path);
+ FilePath file_path(path_str);
+
+ automation_client_->LoadExpandedExtension(file_path, NULL);
+ return S_OK;
+ }
+
// Returns the vector of event handlers for a given event (e.g. "load").
// If the event type isn't recognized, the function fills in a descriptive
// error (IErrorInfo) and returns E_INVALIDARG.
HRESULT GetHandlersForEvent(BSTR event_type, EventHandlers** handlers) {
DCHECK(handlers != NULL);
+ // TODO(tommi): make these if() statements data-driven.
HRESULT hr = S_OK;
const wchar_t* event_type_end = event_type + ::SysStringLen(event_type);
if (LowerCaseEqualsASCII(event_type, event_type_end, "message")) {
@@ -767,13 +820,23 @@ END_MSG_MAP()
"readystatechanged")) {
*handlers = &onreadystatechanged_;
} else if (LowerCaseEqualsASCII(event_type, event_type_end,
- "privatemessage")) {
+ "privatemessage")) {
// This event handler is only available in privileged mode.
- if (!is_privileged_) {
+ if (is_privileged_) {
+ *handlers = &onprivatemessage_;
+ } else {
Error("Event type 'privatemessage' is privileged");
- return E_ACCESSDENIED;
+ hr = E_ACCESSDENIED;
+ }
+ } else if (LowerCaseEqualsASCII(event_type, event_type_end,
+ "extensionready")) {
+ // This event handler is only available in privileged mode.
+ if (is_privileged_) {
+ *handlers = &onextensionready_;
+ } else {
+ Error("Event type 'extensionready' is privileged");
+ hr = E_ACCESSDENIED;
}
- *handlers = &onprivatemessage_;
} else {
Error(StringPrintf("Event type '%ls' not found", event_type).c_str());
hr = E_INVALIDARG;
@@ -896,6 +959,7 @@ END_MSG_MAP()
EventHandlers onload_;
EventHandlers onreadystatechanged_;
EventHandlers onprivatemessage_;
+ EventHandlers onextensionready_;
// The UrlmonUrlRequest instance instantiated for downloading the base URL.
scoped_refptr<CComObject<UrlmonUrlRequest> > base_url_request_;
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc
index 56548de..17fb43d 100644
--- a/chrome_frame/chrome_frame_automation.cc
+++ b/chrome_frame/chrome_frame_automation.cc
@@ -78,6 +78,14 @@ class ChromeFrameAutomationProxyImpl::CFMsgDispatcher
InvokeCallback<Tuple1<AutomationMsg_NavigationResponseValues> >(msg,
origin);
break;
+ case AutomationMsg_InstallExtension::ID:
+ InvokeCallback<Tuple1<AutomationMsg_ExtensionResponseValues> >(msg,
+ origin);
+ break;
+ case AutomationMsg_LoadExpandedExtension::ID:
+ InvokeCallback<Tuple1<AutomationMsg_ExtensionResponseValues> >(msg,
+ origin);
+ break;
default:
NOTREACHED();
}
@@ -598,6 +606,85 @@ void ChromeFrameAutomationClient::FindInPage(const std::wstring& search_string,
automation_server_->SendAsAsync(msg, NULL, this);
}
+// Class that maintains context during the async load/install extension
+// operation. When done, InstallExtensionComplete is posted back to the UI
+// thread so that the users of ChromeFrameAutomationClient can be notified.
+class InstallExtensionContext {
+ public:
+ InstallExtensionContext(ChromeFrameAutomationClient* client,
+ const FilePath& crx_path, void* user_data) : client_(client),
+ crx_path_(crx_path), user_data_(user_data) {
+ }
+
+ ~InstallExtensionContext() {
+ }
+
+ void InstallExtensionComplete(AutomationMsg_ExtensionResponseValues res) {
+ client_->PostTask(FROM_HERE, NewRunnableMethod(client_,
+ &ChromeFrameAutomationClient::InstallExtensionComplete, crx_path_,
+ user_data_, res));
+ delete this;
+ }
+
+ private:
+ ChromeFrameAutomationClient* client_;
+ FilePath crx_path_;
+ void* user_data_;
+};
+
+void ChromeFrameAutomationClient::InstallExtension(
+ const FilePath& crx_path,
+ void* user_data) {
+ if (automation_server_ == NULL) {
+ InstallExtensionComplete(crx_path,
+ user_data,
+ AUTOMATION_MSG_EXTENSION_INSTALL_FAILED);
+ return;
+ }
+
+ InstallExtensionContext* ctx = new InstallExtensionContext(
+ this, crx_path, user_data);
+
+ IPC::SyncMessage* msg =
+ new AutomationMsg_InstallExtension(0, crx_path, NULL);
+
+ // The context will delete itself after it is called.
+ automation_server_->SendAsAsync(msg, NewCallback(ctx,
+ &InstallExtensionContext::InstallExtensionComplete), this);
+}
+
+void ChromeFrameAutomationClient::InstallExtensionComplete(
+ const FilePath& crx_path,
+ void* user_data,
+ AutomationMsg_ExtensionResponseValues res) {
+ DCHECK(PlatformThread::CurrentId() == ui_thread_id_);
+
+ if (chrome_frame_delegate_) {
+ chrome_frame_delegate_->OnExtensionInstalled(crx_path, user_data, res);
+ }
+}
+
+void ChromeFrameAutomationClient::LoadExpandedExtension(
+ const FilePath& path,
+ void* user_data) {
+ if (automation_server_ == NULL) {
+ InstallExtensionComplete(path,
+ user_data,
+ AUTOMATION_MSG_EXTENSION_INSTALL_FAILED);
+ return;
+ }
+
+ InstallExtensionContext* ctx = new InstallExtensionContext(
+ this, path, user_data);
+
+ IPC::SyncMessage* msg =
+ new AutomationMsg_LoadExpandedExtension(0, path, NULL);
+
+ // The context will delete itself after it is called.
+ automation_server_->SendAsAsync(msg, NewCallback(ctx,
+ &InstallExtensionContext::InstallExtensionComplete), this);
+}
+
void ChromeFrameAutomationClient::CreateExternalTab() {
AutomationLaunchResult launch_result = AUTOMATION_SUCCESS;
DCHECK(IsWindow());
diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h
index a1d6d55..e1a34d7 100644
--- a/chrome_frame/chrome_frame_automation.h
+++ b/chrome_frame/chrome_frame_automation.h
@@ -209,6 +209,15 @@ class ChromeFrameAutomationClient
FindInPageCase match_case,
bool find_next);
+ virtual void InstallExtension(const FilePath& crx_path, void* user_data);
+
+ virtual void LoadExpandedExtension(const FilePath& path, void* user_data);
+
+ virtual void InstallExtensionComplete(
+ const FilePath& path,
+ void* user_data,
+ AutomationMsg_ExtensionResponseValues res);
+
TabProxy* tab() const { return tab_.get(); }
BEGIN_MSG_MAP(ChromeFrameAutomationClient)
diff --git a/chrome_frame/chrome_frame_delegate.h b/chrome_frame/chrome_frame_delegate.h
index a886229..e11f099 100644
--- a/chrome_frame/chrome_frame_delegate.h
+++ b/chrome_frame/chrome_frame_delegate.h
@@ -21,6 +21,10 @@ class ChromeFrameDelegate {
virtual void OnAutomationServerReady() = 0;
virtual void OnAutomationServerLaunchFailed(
AutomationLaunchResult reason, const std::string& server_version) = 0;
+ virtual void OnExtensionInstalled(
+ const FilePath& path,
+ void* user_data,
+ AutomationMsg_ExtensionResponseValues response) = 0;
virtual void OnMessageReceived(const IPC::Message& msg) = 0;
// This remains in interface since we call it if Navigate()
@@ -52,8 +56,13 @@ class ChromeFrameDelegateImpl : public ChromeFrameDelegate {
virtual void OnAutomationServerReady() {}
virtual void OnAutomationServerLaunchFailed(
AutomationLaunchResult reason, const std::string& server_version) {}
+ virtual void OnExtensionInstalled(
+ const FilePath& path,
+ void* user_data,
+ AutomationMsg_ExtensionResponseValues response) {}
virtual void OnLoadFailed(int error_code, const std::string& url) {}
virtual void OnMessageReceived(const IPC::Message& msg);
+
static bool IsTabMessage(const IPC::Message& message, int* tab_handle);
virtual bool IsValid() const {
diff --git a/chrome_frame/chrome_frame_npapi.cc b/chrome_frame/chrome_frame_npapi.cc
index e1c5548..6c9791f 100644
--- a/chrome_frame/chrome_frame_npapi.cc
+++ b/chrome_frame/chrome_frame_npapi.cc
@@ -55,11 +55,15 @@ const NPUTF8* ChromeFrameNPAPI::plugin_property_identifier_names_[] = {
const NPUTF8* ChromeFrameNPAPI::plugin_method_identifier_names_[] = {
"postMessage",
"postPrivateMessage",
+ "installExtension",
+ "loadExtension",
};
ChromeFrameNPAPI::PluginMethod ChromeFrameNPAPI::plugin_methods_[] = {
&ChromeFrameNPAPI::postMessage,
&ChromeFrameNPAPI::postPrivateMessage,
+ &ChromeFrameNPAPI::installExtension,
+ &ChromeFrameNPAPI::loadExtension,
};
NPIdentifier
@@ -1383,6 +1387,87 @@ bool ChromeFrameNPAPI::postPrivateMessage(NPObject* npobject,
return true;
}
+bool ChromeFrameNPAPI::installExtension(NPObject* npobject,
+ const NPVariant* args,
+ uint32_t arg_count,
+ NPVariant* result) {
+ if (arg_count > 2 || !NPVARIANT_IS_STRING(args[0]) ||
+ (arg_count == 2 && !NPVARIANT_IS_OBJECT(args[1]))) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (!is_privileged_) {
+ DLOG(WARNING) << "installExtension invoked in non-privileged mode";
+ return false;
+ }
+
+ if (!automation_client_.get()) {
+ DLOG(WARNING) << "installExtension invoked with no automaton client";
+ NOTREACHED();
+ return false;
+ }
+
+ const NPString& crx_path_str = args[0].value.stringValue;
+ std::string crx_path_a(crx_path_str.UTF8Characters, crx_path_str.UTF8Length);
+ FilePath::StringType crx_path_u(UTF8ToWide(crx_path_a));
+ FilePath crx_path(crx_path_u);
+ NPObject* retained_function = npapi::RetainObject(args[1].value.objectValue);
+
+ automation_client_->InstallExtension(crx_path, retained_function);
+ // The response to this command will be returned in the OnExtensionInstalled
+ // delegate callback function.
+
+ return true;
+}
+
+void ChromeFrameNPAPI::OnExtensionInstalled(
+ const FilePath& path,
+ void* user_data,
+ AutomationMsg_ExtensionResponseValues res) {
+ ScopedNpVariant result;
+ NPVariant param;
+ INT32_TO_NPVARIANT(res, param);
+ NPObject* func = reinterpret_cast<NPObject*>(user_data);
+
+ InvokeDefault(func, param, &result);
+ npapi::ReleaseObject(func);
+}
+
+bool ChromeFrameNPAPI::loadExtension(NPObject* npobject,
+ const NPVariant* args,
+ uint32_t arg_count,
+ NPVariant* result) {
+ if (arg_count > 2 || !NPVARIANT_IS_STRING(args[0]) ||
+ (arg_count == 2 && !NPVARIANT_IS_OBJECT(args[1]))) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (!is_privileged_) {
+ DLOG(WARNING) << "loadExtension invoked in non-privileged mode";
+ return false;
+ }
+
+ if (!automation_client_.get()) {
+ DLOG(WARNING) << "loadExtension invoked with no automaton client";
+ NOTREACHED();
+ return false;
+ }
+
+ const NPString& path_str = args[0].value.stringValue;
+ std::string path_a(path_str.UTF8Characters, path_str.UTF8Length);
+ FilePath::StringType path_u(UTF8ToWide(path_a));
+ FilePath path(path_u);
+ NPObject* retained_function = npapi::RetainObject(args[1].value.objectValue);
+
+ automation_client_->LoadExpandedExtension(path, retained_function);
+ // The response to this command will be returned in the OnExtensionInstalled
+ // delegate callback function.
+
+ return true;
+}
+
void ChromeFrameNPAPI::FireEvent(const std::string& event_type,
const std::string& data) {
NPVariant arg;
diff --git a/chrome_frame/chrome_frame_npapi.h b/chrome_frame/chrome_frame_npapi.h
index 005d72f..df35ce3 100644
--- a/chrome_frame/chrome_frame_npapi.h
+++ b/chrome_frame/chrome_frame_npapi.h
@@ -151,6 +151,8 @@ END_MSG_MAP()
virtual void OnAutomationServerReady();
virtual void OnAutomationServerLaunchFailed(
AutomationLaunchResult reason, const std::string& server_version);
+ virtual void OnExtensionInstalled(const FilePath& path,
+ void* user_data, AutomationMsg_ExtensionResponseValues response);
private:
void SubscribeToFocusEvents();
@@ -196,6 +198,14 @@ END_MSG_MAP()
bool postPrivateMessage(NPObject* npobject, const NPVariant* args,
uint32_t arg_count, NPVariant* result);
+ // This method is only available when the control is in privileged mode.
+ bool installExtension(NPObject* npobject, const NPVariant* args,
+ uint32_t arg_count, NPVariant* result);
+
+ // This method is only available when the control is in privileged mode.
+ bool loadExtension(NPObject* npobject, const NPVariant* args,
+ uint32_t arg_count, NPVariant* result);
+
// Pointers to method implementations.
static PluginMethod plugin_methods_[];
diff --git a/chrome_frame/chrome_launcher.cc b/chrome_frame/chrome_launcher.cc
index 3ac0cc5..d7cca9c 100644
--- a/chrome_frame/chrome_launcher.cc
+++ b/chrome_frame/chrome_launcher.cc
@@ -24,7 +24,6 @@ const char* kAllowedSwitches[] = {
switches::kDisableMetrics,
switches::kNoFirstRun,
switches::kUserDataDir,
- switches::kLoadExtension,
switches::kEnableRendererAccessibility,
switches::kNoErrorDialogs,
};
diff --git a/chrome_frame/chrome_launcher_unittest.cc b/chrome_frame/chrome_launcher_unittest.cc
index 268369d..ca140801 100644
--- a/chrome_frame/chrome_launcher_unittest.cc
+++ b/chrome_frame/chrome_launcher_unittest.cc
@@ -1,49 +1,48 @@
-// Copyright (c) 2009 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/command_line.h"
-#include "base/logging.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome_frame/chrome_launcher.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-// Utility class to disable logging. Required to disable DCHECKs that some
-// of our tests would otherwise trigger.
-class LogDisabler {
- public:
- LogDisabler() {
- initial_log_level_ = logging::GetMinLogLevel();
- logging::SetMinLogLevel(logging::LOG_FATAL + 1);
- }
-
- ~LogDisabler() {
- logging::SetMinLogLevel(initial_log_level_);
- }
-
- private:
- int initial_log_level_;
-};
-
-} // namespace
-
-TEST(ChromeLauncher, SanitizeCommandLine) {
- CommandLine bad(L"dummy.exe");
- bad.AppendSwitch(switches::kDisableMetrics); // in whitelist
- bad.AppendSwitchWithValue(switches::kLoadExtension, L"foo"); // in whitelist
- bad.AppendSwitch("no-such-switch"); // does not exist
- bad.AppendSwitch(switches::kHomePage); // exists but not in whitelist
-
- LogDisabler no_dchecks;
-
- CommandLine sanitized(L"dumbo.exe");
- chrome_launcher::SanitizeCommandLine(bad, &sanitized);
- EXPECT_TRUE(sanitized.HasSwitch(switches::kDisableMetrics));
- EXPECT_TRUE(sanitized.HasSwitch(switches::kLoadExtension));
- EXPECT_FALSE(sanitized.HasSwitch("no-such-switch"));
- EXPECT_FALSE(sanitized.HasSwitch(switches::kHomePage));
-
- EXPECT_EQ(sanitized.GetSwitchValue(switches::kLoadExtension), L"foo");
-}
+// Copyright (c) 2009 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/command_line.h"
+#include "base/logging.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome_frame/chrome_launcher.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Utility class to disable logging. Required to disable DCHECKs that some
+// of our tests would otherwise trigger.
+class LogDisabler {
+ public:
+ LogDisabler() {
+ initial_log_level_ = logging::GetMinLogLevel();
+ logging::SetMinLogLevel(logging::LOG_FATAL + 1);
+ }
+
+ ~LogDisabler() {
+ logging::SetMinLogLevel(initial_log_level_);
+ }
+
+ private:
+ int initial_log_level_;
+};
+
+} // namespace
+
+TEST(ChromeLauncher, SanitizeCommandLine) {
+ CommandLine bad(L"dummy.exe");
+ bad.AppendSwitch(switches::kDisableMetrics); // in whitelist
+ bad.AppendSwitchWithValue(switches::kLoadExtension, L"foo"); // in whitelist
+ bad.AppendSwitch("no-such-switch"); // does not exist
+ bad.AppendSwitch(switches::kHomePage); // exists but not in whitelist
+
+ LogDisabler no_dchecks;
+
+ CommandLine sanitized(L"dumbo.exe");
+ chrome_launcher::SanitizeCommandLine(bad, &sanitized);
+ EXPECT_TRUE(sanitized.HasSwitch(switches::kDisableMetrics));
+ EXPECT_FALSE(sanitized.HasSwitch(switches::kLoadExtension));
+ EXPECT_FALSE(sanitized.HasSwitch("no-such-switch"));
+ EXPECT_FALSE(sanitized.HasSwitch(switches::kHomePage));
+}
+
diff --git a/chrome_frame/chrome_tab.idl b/chrome_frame/chrome_tab.idl
index 6f8a2ac..afb364e 100644
--- a/chrome_frame/chrome_tab.idl
+++ b/chrome_frame/chrome_tab.idl
@@ -11,7 +11,7 @@ import "ocidl.idl";
[
object,
- uuid(B9F5EA20-C450-4f46-B70F-BFD3CA9A20C5),
+ uuid(FB243E4B-8AC2-4840-95F2-91B9AF9CFF10),
dual,
nonextensible,
helpstring("IChromeFrame Interface"),
@@ -65,6 +65,14 @@ interface IChromeFrame : IDispatch {
HRESULT useChromeNetwork([out, retval] VARIANT_BOOL* pVal);
[propput, id(11)]
HRESULT useChromeNetwork([in] VARIANT_BOOL newVal);
+
+ [id(12), hidden]
+ // This method is available only when the control is in privileged mode.
+ HRESULT installExtension([in] BSTR crx_path);
+
+ [id(13), hidden]
+ // This method is available only when the control is in privileged mode.
+ HRESULT loadExtension([in] BSTR extension_path);
};
[
@@ -95,6 +103,7 @@ typedef enum {
CF_EVENT_DISPID_ONLOADERROR,
CF_EVENT_DISPID_ONMESSAGE,
CF_EVENT_DISPID_ONPRIVATEMESSAGE,
+ CF_EVENT_DISPID_ONEXTENSIONREADY,
CF_EVENT_DISPID_ONREADYSTATECHANGED = DISPID_READYSTATECHANGE,
} ChromeFrameEventDispId;
@@ -106,7 +115,7 @@ typedef enum {
library ChromeTabLib {
importlib("stdole2.tlb");
- [uuid(A96B8A02-DD11-4936-8C0F-B2520289FABB)]
+ [uuid(388B5D64-CE67-415b-9B0F-745C56E868E7)]
dispinterface DIChromeFrameEvents {
properties:
// None.
@@ -123,6 +132,10 @@ library ChromeTabLib {
[id(CF_EVENT_DISPID_ONPRIVATEMESSAGE)]
// This event is only fired when the control is in privileged mode.
void onprivatemessage([in] IDispatch* event, [in] BSTR target);
+ [id(CF_EVENT_DISPID_ONEXTENSIONREADY)]
+ // This event is only fired when the control is in privileged mode.
+ // response is one of AutomationMsg_ExtensionResponseValues.
+ void onextensionready([in] BSTR path, [in] long response);
};
[uuid(BB1176EE-20DD-41DC-9D1E-AC1335C7BBB0)]
diff --git a/chrome_frame/test/data/privileged_apis_host.html b/chrome_frame/test/data/privileged_apis_host.html
index 7261704..fde39e1 100644
--- a/chrome_frame/test/data/privileged_apis_host.html
+++ b/chrome_frame/test/data/privileged_apis_host.html
@@ -25,16 +25,15 @@
onFailure(testName, 1, 'exception in OnChromeFrameMessage');
}
}
-
- function OnChromeFrameLoaded(url) {
+
+ function tryPrivateMessage() {
var cf = GetChromeFrame();
-
+
try {
// Any message received by this listener is a failure.
// This succeeds in FF, but throws an exception in IE.
cf.addEventListener('onprivatemessage', OnPrivateMessage, false);
} catch(e) {
- cf.onprivatemessage =
appendStatus('addEventListener onprivatemessage threw exception')
}
@@ -46,11 +45,50 @@
} catch(e) {
}
appendStatus('After postPrivateMessage')
- // The frame reflects this twice, first to a bogus target
- // and again to the default target '*'. We succeed if we
+ }
+
+ function tryInstallExtension() {
+ var cf = GetChromeFrame();
+
+ try {
+ // Any message received by this listener is a failure.
+ // This succeeds in FF, but throws an exception in IE.
+ cf.installExtension('foo');
+ onFailure(testName, 1, 'installExtension should throw');
+ } catch(e) {
+ appendStatus('installExtension threw exception')
+ }
+
+ appendStatus('After installExtension')
+ }
+
+ function tryLoadExtension() {
+ var cf = GetChromeFrame();
+
+ try {
+ // Any message received by this listener is a failure.
+ // This succeeds in FF, but throws an exception in IE.
+ cf.loadExtension('foo');
+ onFailure(testName, 1, 'loadExtension should throw');
+ } catch(e) {
+ appendStatus('loadExtension threw exception')
+ }
+
+ appendStatus('After loadExtension')
+ }
+
+ function OnChromeFrameLoaded(url) {
+ tryPrivateMessage();
+ tryInstallExtension();
+ tryLoadExtension();
+
+ // The frame reflects this twice, first to a bogus target
+ // and again to the default target '*'. We succeed if we
// get the reflected message to OnChromeFrameMessage and not to
// OnPrivateMessage.
+ var cf = GetChromeFrame();
cf.postMessage('succeed');
+ appendStatus('After cf.postMessage')
}
function GetChromeFrame() {