summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/resources
diff options
context:
space:
mode:
authorrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-22 06:01:32 +0000
committerrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-22 06:01:32 +0000
commitd7424eb95597971eb17f0858af0ebe1e2a74072c (patch)
tree710a9d75556c5ad3064b20e4f0881a4dd241c2af /chrome/renderer/resources
parent1810cfccee05909e1d9cfa2684a401f71be7b4f5 (diff)
downloadchromium_src-d7424eb95597971eb17f0858af0ebe1e2a74072c.zip
chromium_src-d7424eb95597971eb17f0858af0ebe1e2a74072c.tar.gz
chromium_src-d7424eb95597971eb17f0858af0ebe1e2a74072c.tar.bz2
Validation of extension api callbacks and event parameters in DEBUG
BUG=18711 Review URL: http://codereview.chromium.org/173034 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24068 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/resources')
-rw-r--r--chrome/renderer/resources/event_bindings.js25
-rw-r--r--chrome/renderer/resources/extension_process_bindings.js68
2 files changed, 74 insertions, 19 deletions
diff --git a/chrome/renderer/resources/event_bindings.js b/chrome/renderer/resources/event_bindings.js
index 5fb16f9..3def161 100644
--- a/chrome/renderer/resources/event_bindings.js
+++ b/chrome/renderer/resources/event_bindings.js
@@ -24,9 +24,24 @@ var chrome = chrome || {};
// chrome.tabs.onChanged.addListener(function(data) { alert(data); });
// chromeHidden.Event.dispatch("tab-changed", "hi");
// will result in an alert dialog that says 'hi'.
- chrome.Event = function(opt_eventName) {
+ chrome.Event = function(opt_eventName, opt_argSchemas) {
this.eventName_ = opt_eventName;
this.listeners_ = [];
+
+ // Validate event parameters if we are in debug.
+ if (opt_argSchemas &&
+ chromeHidden.validateCallbacks &&
+ chromeHidden.validate) {
+
+ this.validate_ = function(args) {
+ try {
+ chromeHidden.validate(args, opt_argSchemas);
+ } catch (exception) {
+ return "Event validation error during " + opt_eventName + " -- " +
+ exception;
+ }
+ }
+ }
};
// A map of event names to the event object that is registered to that name.
@@ -45,7 +60,7 @@ var chrome = chrome || {};
if (args) {
args = JSON.parse(args);
}
- attachedNamedEvents[name].dispatch.apply(
+ return attachedNamedEvents[name].dispatch.apply(
attachedNamedEvents[name], args);
}
};
@@ -106,6 +121,12 @@ var chrome = chrome || {};
// arguments to this function each listener.
chrome.Event.prototype.dispatch = function(varargs) {
var args = Array.prototype.slice.call(arguments);
+ if (this.validate_) {
+ var validationErrors = this.validate_(args);
+ if (validationErrors) {
+ return validationErrors;
+ }
+ }
for (var i = 0; i < this.listeners_.length; i++) {
try {
this.listeners_[i].apply(null, args);
diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js
index 3155c05..66872f9 100644
--- a/chrome/renderer/resources/extension_process_bindings.js
+++ b/chrome/renderer/resources/extension_process_bindings.js
@@ -26,13 +26,15 @@ var chrome = chrome || {};
var chromeHidden = GetChromeHidden();
// Validate arguments.
- function validate(args, schemas) {
+ chromeHidden.validationTypes = [];
+ chromeHidden.validate = function(args, schemas) {
if (args.length > schemas.length)
throw new Error("Too many arguments.");
for (var i = 0; i < schemas.length; i++) {
if (i in args && args[i] !== null && args[i] !== undefined) {
var validator = new chrome.JSONSchemaValidator();
+ validator.addTypes(chromeHidden.validationTypes);
validator.validate(args[i], schemas[i]);
if (validator.errors.length == 0)
continue;
@@ -57,10 +59,11 @@ var chrome = chrome || {};
}
// Callback handling.
- var callbacks = [];
+ var requests = [];
chromeHidden.handleResponse = function(requestId, name,
success, response, error) {
try {
+ var request = requests[requestId];
if (success) {
delete chrome.extension.lastError;
} else {
@@ -72,16 +75,41 @@ var chrome = chrome || {};
"message": error
};
}
+
+ if (request.callback) {
+ // Callbacks currently only support one callback argument.
+ var callbackArgs = response ? [JSON.parse(response)] : [];
+
+ // Validate callback in debug only -- and only when the
+ // caller has provided a callback. Implementations of api
+ // calls my not return data if they observe the caller
+ // has not provided a callback.
+ if (chromeHidden.validateCallbacks && !error) {
+ try {
+ if (!request.callbackSchema.parameters) {
+ throw "No callback schemas defined";
+ }
+
+ if (request.callbackSchema.parameters.length > 1) {
+ throw "Callbacks may only define one parameter";
+ }
+
+ chromeHidden.validate(callbackArgs,
+ request.callbackSchema.parameters);
+ } catch (exception) {
+ return "Callback validation error during " + name + " -- " +
+ exception;
+ }
+ }
- if (callbacks[requestId]) {
if (response) {
- callbacks[requestId](JSON.parse(response));
+ request.callback(callbackArgs[0]);
} else {
- callbacks[requestId]();
+ request.callback();
}
}
} finally {
- delete callbacks[requestId];
+ delete requests[requestId];
delete chrome.extension.lastError;
}
};
@@ -89,15 +117,16 @@ var chrome = chrome || {};
function prepareRequest(args, argSchemas) {
var request = {};
var argCount = args.length;
-
+
// Look for callback param.
if (argSchemas.length > 0 &&
args.length == argSchemas.length &&
argSchemas[argSchemas.length - 1].type == "function") {
request.callback = args[argSchemas.length - 1];
+ request.callbackSchema = argSchemas[argSchemas.length - 1];
--argCount;
}
-
+
// Calls with one argument expect singular argument. Calls with multiple
// expect a list.
if (argCount == 1) {
@@ -121,12 +150,9 @@ var chrome = chrome || {};
request.args = null;
var sargs = JSON.stringify(request.args);
var requestId = GetNextRequestId();
- var hasCallback = false;
- if (request.callback) {
- hasCallback = true;
- callbacks[requestId] = request.callback;
- }
- return StartRequest(functionName, sargs, requestId, hasCallback);
+ requests[requestId] = request;
+ return StartRequest(functionName, sargs, requestId,
+ request.callback ? true : false);
}
// Using forEach for convenience, and to bind |module|s & |apiDefs|s via
@@ -179,7 +205,14 @@ var chrome = chrome || {};
forEach(apiDefinitions, function(apiDef) {
chrome[apiDef.namespace] = chrome[apiDef.namespace] || {};
var module = chrome[apiDef.namespace];
-
+
+ // Add types to global validationTypes
+ if (apiDef.types) {
+ forEach(apiDef.types, function(t) {
+ chromeHidden.validationTypes.push(t);
+ });
+ }
+
// Setup Functions.
if (apiDef.functions) {
forEach(apiDef.functions, function(functionDef) {
@@ -194,7 +227,7 @@ var chrome = chrome || {};
apiFunctions[apiFunction.name] = apiFunction;
module[functionDef.name] = bind(apiFunction, function() {
- validate(arguments, this.definition.parameters);
+ chromeHidden.validate(arguments, this.definition.parameters);
if (this.handleRequest)
return this.handleRequest.apply(this, arguments);
@@ -214,7 +247,8 @@ var chrome = chrome || {};
return;
var eventName = apiDef.namespace + "." + eventDef.name;
- module[eventDef.name] = new chrome.Event(eventName);
+ module[eventDef.name] = new chrome.Event(eventName,
+ eventDef.parameters);
});
}
});