OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // This script contains privileged chrome extension related javascript APIs. | 5 // This script contains privileged chrome extension related javascript APIs. |
6 // It is loaded by pages whose URL has the chrome-extension protocol. | 6 // It is loaded by pages whose URL has the chrome-extension protocol. |
7 | 7 |
8 var chrome = chrome || {}; | 8 var chrome = chrome || {}; |
9 (function() { | 9 (function() { |
10 native function GetChromeHidden(); | 10 native function GetChromeHidden(); |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 throw new Error( | 237 throw new Error( |
238 "Either the path or imageData property must be specified."); | 238 "Either the path or imageData property must be specified."); |
239 } | 239 } |
240 } | 240 } |
241 | 241 |
242 // Stores the name and definition of each API function, with methods to | 242 // Stores the name and definition of each API function, with methods to |
243 // modify their behaviour (such as a custom way to handle requests to the | 243 // modify their behaviour (such as a custom way to handle requests to the |
244 // API, a custom callback, etc). | 244 // API, a custom callback, etc). |
245 function APIFunctions() { | 245 function APIFunctions() { |
246 this._apiFunctions = {}; | 246 this._apiFunctions = {}; |
| 247 this._unavailableApiFunctions = {}; |
247 } | 248 } |
248 APIFunctions.prototype.register = function(apiName, apiFunction) { | 249 APIFunctions.prototype.register = function(apiName, apiFunction) { |
249 this._apiFunctions[apiName] = apiFunction; | 250 this._apiFunctions[apiName] = apiFunction; |
250 }; | 251 }; |
| 252 // Registers a function as existing but not available, meaning that calls to |
| 253 // the set* methods that reference this function should be ignored rather |
| 254 // than throwing Errors. |
| 255 APIFunctions.prototype.registerUnavailable = function(apiName) { |
| 256 this._unavailableApiFunctions[apiName] = apiName; |
| 257 }; |
251 APIFunctions.prototype._setHook = | 258 APIFunctions.prototype._setHook = |
252 function(apiName, propertyName, customizedFunction) { | 259 function(apiName, propertyName, customizedFunction) { |
253 if (this._apiFunctions.hasOwnProperty(apiName)) | 260 if (this._unavailableApiFunctions.hasOwnProperty(apiName)) |
254 this._apiFunctions[apiName][propertyName] = customizedFunction; | 261 return; |
| 262 if (!this._apiFunctions.hasOwnProperty(apiName)) |
| 263 throw new Error('Tried to set hook for unknown API "' + apiName + '"'); |
| 264 this._apiFunctions[apiName][propertyName] = customizedFunction; |
255 }; | 265 }; |
256 APIFunctions.prototype.setHandleRequest = | 266 APIFunctions.prototype.setHandleRequest = |
257 function(apiName, customizedFunction) { | 267 function(apiName, customizedFunction) { |
258 return this._setHook(apiName, 'handleRequest', customizedFunction); | 268 return this._setHook(apiName, 'handleRequest', customizedFunction); |
259 }; | 269 }; |
260 APIFunctions.prototype.setUpdateArgumentsPostValidate = | 270 APIFunctions.prototype.setUpdateArgumentsPostValidate = |
261 function(apiName, customizedFunction) { | 271 function(apiName, customizedFunction) { |
262 return this._setHook( | 272 return this._setHook( |
263 apiName, 'updateArgumentsPostValidate', customizedFunction); | 273 apiName, 'updateArgumentsPostValidate', customizedFunction); |
264 }; | 274 }; |
265 APIFunctions.prototype.setUpdateArgumentsPreValidate = | 275 APIFunctions.prototype.setUpdateArgumentsPreValidate = |
266 function(apiName, customizedFunction) { | 276 function(apiName, customizedFunction) { |
267 return this._setHook( | 277 return this._setHook( |
268 apiName, 'updateArgumentsPreValidate', customizedFunction); | 278 apiName, 'updateArgumentsPreValidate', customizedFunction); |
269 }; | 279 }; |
270 APIFunctions.prototype.setCustomCallback = | 280 APIFunctions.prototype.setCustomCallback = |
271 function(apiName, customizedFunction) { | 281 function(apiName, customizedFunction) { |
272 return this._setHook(apiName, 'customCallback', customizedFunction); | 282 return this._setHook(apiName, 'customCallback', customizedFunction); |
273 }; | 283 }; |
274 | 284 |
275 var apiFunctions = new APIFunctions(); | 285 var apiFunctions = new APIFunctions(); |
276 | 286 |
| 287 // Wraps the calls to the set* methods of APIFunctions with the namespace of |
| 288 // an API, and validates that all calls to set* methods aren't prefixed with |
| 289 // a namespace. |
| 290 // |
| 291 // For example, if constructed with 'browserAction', a call to |
| 292 // handleRequest('foo') will be transformed into |
| 293 // handleRequest('browserAction.foo'). |
| 294 // |
| 295 // Likewise, if a call to handleRequest is called with 'browserAction.foo', |
| 296 // it will throw an error. |
| 297 // |
| 298 // These help with isolating custom bindings from each other. |
| 299 function NamespacedAPIFunctions(namespace, delegate) { |
| 300 var self = this; |
| 301 function wrap(methodName) { |
| 302 self[methodName] = function(apiName, customizedFunction) { |
| 303 var prefix = namespace + '.'; |
| 304 if (apiName.indexOf(prefix) === 0) { |
| 305 throw new Error(methodName + ' called with "' + apiName + |
| 306 '" which has a "' + prefix + '" prefix. ' + |
| 307 'This is unnecessary and must be left out.'); |
| 308 } |
| 309 return delegate[methodName].call(delegate, |
| 310 prefix + apiName, customizedFunction); |
| 311 }; |
| 312 } |
| 313 |
| 314 wrap('contains'); |
| 315 wrap('setHandleRequest'); |
| 316 wrap('setUpdateArgumentsPostValidate'); |
| 317 wrap('setUpdateArgumentsPreValidate'); |
| 318 wrap('setCustomCallback'); |
| 319 } |
| 320 |
277 // | 321 // |
278 // The API through which the ${api_name}_custom_bindings.js files customize | 322 // The API through which the ${api_name}_custom_bindings.js files customize |
279 // their API bindings beyond what can be generated. | 323 // their API bindings beyond what can be generated. |
280 // | 324 // |
281 // There are 2 types of customizations available: those which are required in | 325 // There are 2 types of customizations available: those which are required in |
282 // order to do the schema generation (registerCustomEvent and | 326 // order to do the schema generation (registerCustomEvent and |
283 // registerCustomType), and those which can only run after the bindings have | 327 // registerCustomType), and those which can only run after the bindings have |
284 // been generated (registerCustomHook). | 328 // been generated (registerCustomHook). |
285 // | 329 // |
286 | 330 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
423 }); | 467 }); |
424 } | 468 } |
425 | 469 |
426 // Setup Functions. | 470 // Setup Functions. |
427 if (apiDef.functions) { | 471 if (apiDef.functions) { |
428 apiDef.functions.forEach(function(functionDef) { | 472 apiDef.functions.forEach(function(functionDef) { |
429 if (functionDef.name in mod) { | 473 if (functionDef.name in mod) { |
430 throw new Error('Function ' + functionDef.name + | 474 throw new Error('Function ' + functionDef.name + |
431 ' already defined in ' + apiDef.namespace); | 475 ' already defined in ' + apiDef.namespace); |
432 } | 476 } |
433 if (!isSchemaNodeSupported(functionDef, platform, manifestVersion)) | 477 |
| 478 var apiFunctionName = apiDef.namespace + "." + functionDef.name; |
| 479 |
| 480 if (!isSchemaNodeSupported(functionDef, platform, manifestVersion)) { |
| 481 apiFunctions.registerUnavailable(apiFunctionName); |
434 return; | 482 return; |
| 483 } |
435 if (!isSchemaAccessAllowed(functionDef)) { | 484 if (!isSchemaAccessAllowed(functionDef)) { |
| 485 apiFunctions.registerUnavailable(apiFunctionName); |
436 addUnprivilegedAccessGetter(mod, functionDef.name); | 486 addUnprivilegedAccessGetter(mod, functionDef.name); |
437 return; | 487 return; |
438 } | 488 } |
439 | 489 |
440 var apiFunction = {}; | 490 var apiFunction = {}; |
441 apiFunction.definition = functionDef; | 491 apiFunction.definition = functionDef; |
442 apiFunction.name = apiDef.namespace + "." + functionDef.name; | 492 apiFunction.name = apiFunctionName; |
443 apiFunctions.register(apiFunction.name, apiFunction); | 493 apiFunctions.register(apiFunctionName, apiFunction); |
444 | 494 |
445 mod[functionDef.name] = (function() { | 495 mod[functionDef.name] = (function() { |
446 var args = arguments; | 496 var args = arguments; |
447 if (this.updateArgumentsPreValidate) | 497 if (this.updateArgumentsPreValidate) |
448 args = this.updateArgumentsPreValidate.apply(this, args); | 498 args = this.updateArgumentsPreValidate.apply(this, args); |
449 chromeHidden.validate(args, this.definition.parameters); | 499 chromeHidden.validate(args, this.definition.parameters); |
450 if (this.updateArgumentsPostValidate) | 500 if (this.updateArgumentsPostValidate) |
451 args = this.updateArgumentsPostValidate.apply(this, args); | 501 args = this.updateArgumentsPostValidate.apply(this, args); |
452 | 502 |
453 var retval; | 503 var retval; |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 return; | 607 return; |
558 | 608 |
559 var hook = customHooks[apiDef.namespace]; | 609 var hook = customHooks[apiDef.namespace]; |
560 if (!hook) | 610 if (!hook) |
561 return; | 611 return; |
562 | 612 |
563 // Pass through the public API of schema_generated_bindings, to be used | 613 // Pass through the public API of schema_generated_bindings, to be used |
564 // by custom bindings JS files. Create a new one so that bindings can't | 614 // by custom bindings JS files. Create a new one so that bindings can't |
565 // interfere with each other. | 615 // interfere with each other. |
566 hook({ | 616 hook({ |
567 apiFunctions: apiFunctions, | 617 apiFunctions: new NamespacedAPIFunctions(apiDef.namespace, |
| 618 apiFunctions), |
568 sendRequest: sendRequest, | 619 sendRequest: sendRequest, |
569 setIcon: setIcon, | 620 setIcon: setIcon, |
570 apiDefinitions: apiDefinitions, | 621 apiDefinitions: apiDefinitions, |
571 }, extensionId); | 622 }, extensionId); |
572 }); | 623 }); |
573 | 624 |
574 // TODO(mihaip): remove this alias once the webstore stops calling | 625 // TODO(mihaip): remove this alias once the webstore stops calling |
575 // beginInstallWithManifest2. | 626 // beginInstallWithManifest2. |
576 // See http://crbug.com/100242 | 627 // See http://crbug.com/100242 |
577 if (chrome.webstorePrivate) { | 628 if (chrome.webstorePrivate) { |
578 chrome.webstorePrivate.beginInstallWithManifest2 = | 629 chrome.webstorePrivate.beginInstallWithManifest2 = |
579 chrome.webstorePrivate.beginInstallWithManifest3; | 630 chrome.webstorePrivate.beginInstallWithManifest3; |
580 } | 631 } |
581 | 632 |
582 if (chrome.test) | 633 if (chrome.test) |
583 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; | 634 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; |
584 }); | 635 }); |
585 })(); | 636 })(); |
OLD | NEW |