Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/renderer/extensions/chrome_app_bindings.h" | 5 #include "chrome/renderer/extensions/chrome_app_bindings.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/json/json_writer.h" | 8 #include "base/json/json_writer.h" |
| 9 #include "base/string16.h" | 9 #include "base/string16.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "base/utf_string_conversions.h" | 11 #include "base/utf_string_conversions.h" |
| 12 #include "base/values.h" | 12 #include "base/values.h" |
| 13 #include "chrome/common/chrome_switches.h" | 13 #include "chrome/common/chrome_switches.h" |
| 14 #include "chrome/common/extensions/extension_set.h" | 14 #include "chrome/common/extensions/extension_set.h" |
| 15 #include "chrome/renderer/extensions/callback_map.h" | |
| 15 #include "chrome/renderer/extensions/extension_dispatcher.h" | 16 #include "chrome/renderer/extensions/extension_dispatcher.h" |
| 16 #include "chrome/renderer/extensions/extension_helper.h" | 17 #include "chrome/renderer/extensions/extension_helper.h" |
| 17 #include "content/renderer/render_view.h" | 18 #include "content/renderer/render_view.h" |
| 18 #include "content/renderer/v8_value_converter.h" | 19 #include "content/renderer/v8_value_converter.h" |
| 19 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" |
| 20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
| 21 #include "v8/include/v8.h" | 22 #include "v8/include/v8.h" |
| 22 | 23 |
| 24 using extensions_v8_util::CallbackMap; | |
| 23 using WebKit::WebFrame; | 25 using WebKit::WebFrame; |
| 24 | 26 |
| 25 namespace { | 27 namespace { |
| 26 | 28 |
| 27 bool IsCheckoutURL(const std::string& url_spec) { | 29 bool IsCheckoutURL(const std::string& url_spec) { |
| 28 std::string checkout_url_prefix = | 30 std::string checkout_url_prefix = |
| 29 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 31 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| 30 switches::kAppsCheckoutURL); | 32 switches::kAppsCheckoutURL); |
| 31 if (checkout_url_prefix.empty()) | 33 if (checkout_url_prefix.empty()) |
| 32 checkout_url_prefix = "https://checkout.google.com/"; | 34 checkout_url_prefix = "https://checkout.google.com/"; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 44 if (!IsCheckoutURL(frame->document().url().spec())) { | 46 if (!IsCheckoutURL(frame->document().url().spec())) { |
| 45 std::string error("Access denied for URL: "); | 47 std::string error("Access denied for URL: "); |
| 46 error += frame->document().url().spec(); | 48 error += frame->document().url().spec(); |
| 47 v8::ThrowException(v8::String::New(error.c_str())); | 49 v8::ThrowException(v8::String::New(error.c_str())); |
| 48 return false; | 50 return false; |
| 49 } | 51 } |
| 50 | 52 |
| 51 return true; | 53 return true; |
| 52 } | 54 } |
| 53 | 55 |
| 56 int g_next_request_id = 0; | |
| 57 base::LazyInstance<CallbackMap> g_callbacks(base::LINKER_INITIALIZED); | |
| 58 | |
| 59 const char* kMissingClientIdError = "Missing clientId parameter"; | |
| 60 const char* kInvalidClientIdError = "Invalid clientId"; | |
| 61 const char* kCallbackNotAFunctionError = | |
| 62 "The callback that was passed is not a function"; | |
| 63 | |
| 54 } // namespace | 64 } // namespace |
| 55 | 65 |
| 56 const char kAppExtensionName[] = "v8/ChromeApp"; | 66 const char kAppExtensionName[] = "v8/ChromeApp"; |
| 57 | 67 |
| 58 namespace extensions_v8 { | 68 namespace extensions_v8 { |
| 59 | 69 |
| 60 class ChromeAppExtensionWrapper : public v8::Extension { | 70 class ChromeAppExtensionWrapper : public v8::Extension { |
| 61 public: | 71 public: |
| 62 explicit ChromeAppExtensionWrapper(ExtensionDispatcher* extension_dispatcher) | 72 explicit ChromeAppExtensionWrapper(ExtensionDispatcher* extension_dispatcher) |
| 63 : v8::Extension( | 73 : v8::Extension( |
| 64 kAppExtensionName, | 74 kAppExtensionName, |
| 65 "var chrome;" | 75 "var chrome;" |
| 66 "if (!chrome)" | 76 "if (!chrome)" |
| 67 " chrome = {};" | 77 " chrome = {};" |
| 68 "if (!chrome.app) {" | 78 "if (!chrome.app) {" |
| 69 " chrome.app = new function() {" | 79 " chrome.app = new function() {" |
| 70 " native function GetIsInstalled();" | 80 " native function GetIsInstalled();" |
| 71 " native function Install();" | 81 " native function Install();" |
| 72 " native function GetDetails();" | 82 " native function GetDetails();" |
| 73 " native function GetDetailsForFrame();" | 83 " native function GetDetailsForFrame();" |
| 84 " native function GetAppNotifyChannel();" | |
| 74 " this.__defineGetter__('isInstalled', GetIsInstalled);" | 85 " this.__defineGetter__('isInstalled', GetIsInstalled);" |
| 75 " this.install = Install;" | 86 " this.install = Install;" |
| 76 " this.getDetails = GetDetails;" | 87 " this.getDetails = GetDetails;" |
| 77 " this.getDetailsForFrame = GetDetailsForFrame;" | 88 " this.getDetailsForFrame = GetDetailsForFrame;" |
| 89 " this.experimental = {};" | |
|
Aaron Boodman
2011/10/03 22:07:43
Hm, is this checked against --enable-experimental-
asargent_no_longer_on_chrome
2011/10/04 00:43:20
Yep - the check is in ExtensionMessageHandler::OnG
| |
| 90 " this.experimental.getNotificationChannel =" | |
| 91 " GetAppNotifyChannel;" | |
| 78 " };" | 92 " };" |
| 79 "}") { | 93 "}") { |
| 80 extension_dispatcher_ = extension_dispatcher; | 94 extension_dispatcher_ = extension_dispatcher; |
| 81 } | 95 } |
| 82 | 96 |
| 83 ~ChromeAppExtensionWrapper() { | 97 ~ChromeAppExtensionWrapper() { |
| 84 extension_dispatcher_ = NULL; | 98 extension_dispatcher_ = NULL; |
| 85 } | 99 } |
| 86 | 100 |
| 87 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( | 101 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( |
| 88 v8::Handle<v8::String> name) { | 102 v8::Handle<v8::String> name) { |
| 89 if (name->Equals(v8::String::New("GetIsInstalled"))) { | 103 if (name->Equals(v8::String::New("GetIsInstalled"))) { |
| 90 return v8::FunctionTemplate::New(GetIsInstalled); | 104 return v8::FunctionTemplate::New(GetIsInstalled); |
| 91 } else if (name->Equals(v8::String::New("Install"))) { | 105 } else if (name->Equals(v8::String::New("Install"))) { |
| 92 return v8::FunctionTemplate::New(Install); | 106 return v8::FunctionTemplate::New(Install); |
| 93 } else if (name->Equals(v8::String::New("GetDetails"))) { | 107 } else if (name->Equals(v8::String::New("GetDetails"))) { |
| 94 return v8::FunctionTemplate::New(GetDetails); | 108 return v8::FunctionTemplate::New(GetDetails); |
| 95 } else if (name->Equals(v8::String::New("GetDetailsForFrame"))) { | 109 } else if (name->Equals(v8::String::New("GetDetailsForFrame"))) { |
| 96 return v8::FunctionTemplate::New(GetDetailsForFrame); | 110 return v8::FunctionTemplate::New(GetDetailsForFrame); |
| 111 } else if (name->Equals(v8::String::New("GetAppNotifyChannel"))) { | |
| 112 return v8::FunctionTemplate::New(GetAppNotifyChannel); | |
| 97 } else { | 113 } else { |
| 98 return v8::Handle<v8::FunctionTemplate>(); | 114 return v8::Handle<v8::FunctionTemplate>(); |
| 99 } | 115 } |
| 100 } | 116 } |
| 101 | 117 |
| 102 static v8::Handle<v8::Value> GetIsInstalled(const v8::Arguments& args) { | 118 static v8::Handle<v8::Value> GetIsInstalled(const v8::Arguments& args) { |
| 103 WebFrame* frame = WebFrame::frameForCurrentContext(); | 119 WebFrame* frame = WebFrame::frameForCurrentContext(); |
| 104 if (!frame) | 120 if (!frame) |
| 105 return v8::False(); | 121 return v8::False(); |
| 106 | 122 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 172 return v8::Null(); | 188 return v8::Null(); |
| 173 | 189 |
| 174 scoped_ptr<DictionaryValue> manifest_copy( | 190 scoped_ptr<DictionaryValue> manifest_copy( |
| 175 extension->manifest_value()->DeepCopy()); | 191 extension->manifest_value()->DeepCopy()); |
| 176 manifest_copy->SetString("id", extension->id()); | 192 manifest_copy->SetString("id", extension->id()); |
| 177 V8ValueConverter converter; | 193 V8ValueConverter converter; |
| 178 return converter.ToV8Value(manifest_copy.get(), | 194 return converter.ToV8Value(manifest_copy.get(), |
| 179 frame->mainWorldScriptContext()); | 195 frame->mainWorldScriptContext()); |
| 180 } | 196 } |
| 181 | 197 |
| 198 static v8::Handle<v8::Value> GetAppNotifyChannel(const v8::Arguments& args) { | |
| 199 WebFrame* frame = WebFrame::frameForCurrentContext(); | |
| 200 if (!frame || !frame->view()) | |
| 201 return v8::Undefined(); | |
| 202 | |
| 203 RenderView* render_view = RenderView::FromWebView(frame->view()); | |
| 204 if (!render_view) | |
| 205 return v8::Undefined(); | |
| 206 | |
| 207 if (g_next_request_id < 0) | |
| 208 return v8::Undefined(); | |
| 209 int request_id = g_next_request_id++; | |
| 210 | |
| 211 // Read the required 'clientId' value out of the object at args[0]. | |
| 212 std::string client_id; | |
| 213 if (args.Length() < 1 || !args[0]->IsObject()) { | |
| 214 v8::ThrowException(v8::String::New(kMissingClientIdError)); | |
| 215 return v8::Undefined(); | |
| 216 } | |
| 217 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(args[0]); | |
| 218 v8::Local<v8::String> client_id_key = v8::String::New("clientId"); | |
| 219 if (obj->Has(client_id_key)) { | |
| 220 v8::String::Utf8Value id_value(obj->Get(client_id_key)); | |
| 221 if (id_value.length() > 0) | |
| 222 client_id = std::string(*id_value); | |
| 223 } | |
| 224 if (client_id.empty()) { | |
| 225 v8::ThrowException(v8::String::New(kInvalidClientIdError)); | |
| 226 return v8::Undefined(); | |
| 227 } | |
| 228 | |
| 229 // Hang on to the callback if there was one. | |
| 230 if (args.Length() >= 2) { | |
| 231 if (args[1]->IsFunction()) { | |
| 232 g_callbacks.Get().Add(request_id, v8::Function::Cast(*args[1])); | |
| 233 } else { | |
| 234 v8::ThrowException(v8::String::New(kCallbackNotAFunctionError)); | |
| 235 return v8::Undefined(); | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 ExtensionHelper* helper = ExtensionHelper::Get(render_view); | |
| 240 helper->GetAppNotifyChannel( | |
| 241 request_id, frame->document().url(), client_id); | |
| 242 return v8::Undefined(); | |
| 243 } | |
| 244 | |
| 182 static ExtensionDispatcher* extension_dispatcher_; | 245 static ExtensionDispatcher* extension_dispatcher_; |
| 183 }; | 246 }; |
| 184 | 247 |
| 185 ExtensionDispatcher* ChromeAppExtensionWrapper::extension_dispatcher_; | 248 ExtensionDispatcher* ChromeAppExtensionWrapper::extension_dispatcher_; |
| 186 | 249 |
| 187 v8::Extension* ChromeAppExtension::Get( | 250 v8::Extension* ChromeAppExtension::Get( |
| 188 ExtensionDispatcher* extension_dispatcher) { | 251 ExtensionDispatcher* extension_dispatcher) { |
| 189 return new ChromeAppExtensionWrapper(extension_dispatcher); | 252 return new ChromeAppExtensionWrapper(extension_dispatcher); |
| 190 } | 253 } |
| 191 | 254 |
| 255 void ChromeAppExtension::HandleGetAppNotifyChannelResponse( | |
| 256 int request_id, const std::string& channel_id, const std::string& error) { | |
| 257 v8::Persistent<v8::Function> function = g_callbacks.Get().Remove(request_id); | |
| 258 if (function.IsEmpty()) | |
| 259 return; | |
| 260 v8::HandleScope handle_scope; | |
| 261 v8::Context::Scope context_scope(function->CreationContext()); | |
| 262 v8::Handle<v8::Value> argv[2]; | |
| 263 argv[0] = v8::String::New(channel_id.c_str()); | |
| 264 argv[1] = v8::String::New(error.c_str()); | |
| 265 function->Call(v8::Object::New(), arraysize(argv), argv); | |
| 266 } | |
| 267 | |
| 192 } // namespace extensions_v8 | 268 } // namespace extensions_v8 |
| OLD | NEW |