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 |