Index: chrome/renderer/resources/extensions/event.js |
diff --git a/chrome/renderer/resources/extensions/event.js b/chrome/renderer/resources/extensions/event.js |
index 81c465b0d83d5150c4402719784de7eb72825fda..8961ce56fc112758d971b496ccaa842b070af33b 100644 |
--- a/chrome/renderer/resources/extensions/event.js |
+++ b/chrome/renderer/resources/extensions/event.js |
@@ -5,8 +5,36 @@ |
var eventBindingsNatives = requireNative('event_bindings'); |
var AttachEvent = eventBindingsNatives.AttachEvent; |
var DetachEvent = eventBindingsNatives.DetachEvent; |
+ var sendRequest = require('sendRequest').sendRequest; |
+ var utils = require('utils'); |
var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); |
+ var GetExtensionAPIDefinition = |
+ requireNative('apiDefinitions').GetExtensionAPIDefinition; |
+ |
+ // Schemas for the rule-style functions on the events API that |
+ // only need to be generated occasionally, so populate them lazily. |
+ var ruleFunctionSchemas = { |
+ // These values are set lazily: |
+ // addRules: {}, |
+ // getRules: {}, |
+ // removeRules: {} |
+ }; |
+ |
+ // This function ensures that |ruleFunctionSchemas| is populated. |
+ function ensureRuleSchemasLoaded() { |
+ if (ruleFunctionSchemas.addRules) |
+ return; |
+ var eventsSchema = GetExtensionAPIDefinition("events")[0]; |
+ var eventType = utils.lookup(eventsSchema.types, 'id', 'events.Event'); |
+ |
+ ruleFunctionSchemas.addRules = |
+ utils.lookup(eventType.functions, 'name', 'addRules'); |
+ ruleFunctionSchemas.getRules = |
+ utils.lookup(eventType.functions, 'name', 'getRules'); |
+ ruleFunctionSchemas.removeRules = |
+ utils.lookup(eventType.functions, 'name', 'removeRules'); |
+ } |
// Local implementation of JSON.parse & JSON.stringify that protect us |
// from being clobbered by an extension. |
@@ -68,12 +96,13 @@ |
if (this.eventOptions_.supportsRules && !opt_eventName) |
throw new Error("Events that support rules require an event name."); |
- // Validate event parameters if we are in debug. |
+ // Validate event arguments (the data that is passed to the callbacks) |
+ // if we are in debug. |
if (opt_argSchemas && |
chromeHidden.validateCallbacks && |
chromeHidden.validate) { |
- this.validate_ = function(args) { |
+ this.validateEventArgs_ = function(args) { |
try { |
chromeHidden.validate(args, opt_argSchemas); |
} catch (exception) { |
@@ -82,7 +111,7 @@ |
} |
}; |
} else { |
- this.validate_ = function() {} |
+ this.validateEventArgs_ = function() {} |
} |
}; |
@@ -192,7 +221,7 @@ |
if (!this.eventOptions_.supportsListeners) |
throw new Error("This event does not support listeners."); |
var args = Array.prototype.slice.call(arguments); |
- var validationErrors = this.validate_(args); |
+ var validationErrors = this.validateEventArgs_(args); |
if (validationErrors) { |
return {validationErrors: validationErrors}; |
} |
@@ -246,49 +275,72 @@ |
chrome.Event.prototype.destroy_ = function() { |
this.listeners_ = []; |
- this.validate_ = []; |
+ this.validateEventArgs_ = []; |
this.detach_(false); |
}; |
- // Gets the declarative API object, or undefined if this extension doesn't |
- // have access to it. |
- // |
- // This is defined as a function (rather than a variable) because it isn't |
- // accessible until the schema bindings have been generated. |
- function getDeclarativeAPI() { |
- return chromeHidden.internalAPIs.declarative; |
- } |
- |
chrome.Event.prototype.addRules = function(rules, opt_cb) { |
if (!this.eventOptions_.supportsRules) |
throw new Error("This event does not support rules."); |
- if (!getDeclarativeAPI()) { |
- throw new Error("You must have permission to use the declarative " + |
- "API to support rules in events"); |
+ |
+ // Takes a list of JSON datatype identifiers and returns a schema fragment |
+ // that verifies that a JSON object corresponds to an array of only these |
+ // data types. |
+ function buildArrayOfChoicesSchema(typesList) { |
+ return { |
+ 'type': 'array', |
+ 'items': { |
+ 'choices': typesList.map(function(el) {return {'$ref': el};}) |
+ } |
+ }; |
+ }; |
+ |
+ // Validate conditions and actions against specific schemas of this |
+ // event object type. |
+ // |rules| is an array of JSON objects that follow the Rule type of the |
+ // declarative extension APIs. |conditions| is an array of JSON type |
+ // identifiers that are allowed to occur in the conditions attribute of each |
+ // rule. Likewise, |actions| is an array of JSON type identifiers that are |
+ // allowed to occur in the actions attribute of each rule. |
+ function validateRules(rules, conditions, actions) { |
+ var conditionsSchema = buildArrayOfChoicesSchema(conditions); |
+ var actionsSchema = buildArrayOfChoicesSchema(actions); |
+ rules.forEach(function(rule) { |
+ chromeHidden.validate([rule.conditions], [conditionsSchema]); |
+ chromeHidden.validate([rule.actions], [actionsSchema]); |
+ }) |
+ }; |
+ |
+ if (!this.eventOptions_.conditions || !this.eventOptions_.actions) { |
+ throw new Error('Event ' + this.eventName_ + ' misses conditions or ' + |
+ 'actions in the API specification.'); |
} |
- getDeclarativeAPI().addRules(this.eventName_, rules, opt_cb); |
+ |
+ validateRules(rules, |
+ this.eventOptions_.conditions, |
+ this.eventOptions_.actions); |
+ |
+ ensureRuleSchemasLoaded(); |
+ sendRequest("events.addRules", [this.eventName_, rules, opt_cb], |
+ ruleFunctionSchemas.addRules.parameters); |
} |
chrome.Event.prototype.removeRules = function(ruleIdentifiers, opt_cb) { |
if (!this.eventOptions_.supportsRules) |
throw new Error("This event does not support rules."); |
- if (!getDeclarativeAPI()) { |
- throw new Error("You must have permission to use the declarative " + |
- "API to support rules in events"); |
- } |
- getDeclarativeAPI().removeRules( |
- this.eventName_, ruleIdentifiers, opt_cb); |
+ ensureRuleSchemasLoaded(); |
+ sendRequest("events.removeRules", |
+ [this.eventName_, ruleIdentifiers, opt_cb], |
+ ruleFunctionSchemas.removeRules.parameters); |
} |
chrome.Event.prototype.getRules = function(ruleIdentifiers, cb) { |
if (!this.eventOptions_.supportsRules) |
throw new Error("This event does not support rules."); |
- if (!getDeclarativeAPI()) { |
- throw new Error("You must have permission to use the declarative " + |
- "API to support rules in events"); |
- } |
- getDeclarativeAPI().getRules( |
- this.eventName_, ruleIdentifiers, cb); |
+ ensureRuleSchemasLoaded(); |
+ sendRequest("events.getRules", |
+ [this.eventName_, ruleIdentifiers, cb], |
+ ruleFunctionSchemas.getRules.parameters); |
} |
// Special load events: we don't use the DOM unload because that slows |