Commit 31bbfd73 authored by kalman@chromium.org's avatar kalman@chromium.org

Make the externally connectable browser test clobber all of the builtins,

except for a very small subset of them, and use the safe builtins to make the
test pass.

This will give us a decent sense of confidence that web pages can't
accidentally override builtins in a way that breaks us, though there are still
infinite ways for an extension to deliberately break itself.

BUG=55316
R=jyasskin@chromium.org

Review URL: https://codereview.chromium.org/17451011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@207995 0039d316-1c4b-4281-b951-d872f2087c98
parent b518fa10
......@@ -189,6 +189,8 @@ v8::Handle<v8::Value> ModuleSystem::RequireForJsInner(
exports = v8::Object::New();
v8::Handle<v8::Object> natives(NewInstance());
CHECK(!natives.IsEmpty()); // this can happen if v8 has issues
// These must match the argument order in WrapSource.
v8::Handle<v8::Value> args[] = {
// CommonJS.
......@@ -200,6 +202,8 @@ v8::Handle<v8::Value> ModuleSystem::RequireForJsInner(
context_->safe_builtins()->GetFunction(),
context_->safe_builtins()->GetJSON(),
context_->safe_builtins()->GetObjekt(),
context_->safe_builtins()->GetRegExp(),
context_->safe_builtins()->GetString(),
};
{
v8::TryCatch try_catch;
......@@ -483,7 +487,7 @@ v8::Handle<v8::String> ModuleSystem::WrapSource(v8::Handle<v8::String> source) {
// Keep in order with the arguments in RequireForJsInner.
v8::Handle<v8::String> left = v8::String::New(
"(function(require, requireNative, exports,"
"$Array, $Function, $JSON, $Object) {"
"$Array, $Function, $JSON, $Object, $RegExp, $String) {"
"'use strict';");
v8::Handle<v8::String> right = v8::String::New("\n})");
return handle_scope.Close(
......
......@@ -150,17 +150,21 @@ class ExtensionImpl : public v8::Extension {
static void Apply(const v8::FunctionCallbackInfo<v8::Value>& info) {
CHECK(info.Length() == 5 &&
info[0]->IsFunction() && // function
// info[1]->Object() // recv (will throw error not check)
// info[1] could be an object or a string
info[2]->IsObject() && // args
info[3]->IsInt32() && // first_arg_index
info[4]->IsInt32()); // args_length
if (!info[1]->IsObject()) {
v8::Local<v8::Function> function = info[0].As<v8::Function>();
v8::Local<v8::Object> recv;
if (info[1]->IsObject()) {
recv = info[1]->ToObject();
} else if (info[1]->IsString()) {
recv = v8::StringObject::New(info[1]->ToString())->ToObject();
} else {
v8::ThrowException(v8::Exception::TypeError(v8::String::New(
"The first argument is the receiver and must be an object")));
return;
}
v8::Local<v8::Function> function = info[0].As<v8::Function>();
v8::Local<v8::Object> recv = info[1]->ToObject();
v8::Local<v8::Object> args = info[2]->ToObject();
int first_arg_index = static_cast<int>(info[3]->ToInt32()->Value());
int args_length = static_cast<int>(info[4]->ToInt32()->Value());
......@@ -214,4 +218,12 @@ v8::Local<v8::Object> SafeBuiltins::GetObjekt() const {
return Load("Object", context_->v8_context());
}
v8::Local<v8::Object> SafeBuiltins::GetRegExp() const {
return Load("RegExp", context_->v8_context());
}
v8::Local<v8::Object> SafeBuiltins::GetString() const {
return Load("String", context_->v8_context());
}
} // namespace extensions
......@@ -34,6 +34,8 @@ class SafeBuiltins {
// NOTE(kalman): VS2010 won't compile "GetObject", it mysteriously renames it
// to "GetObjectW" - hence GetObjekt. Sorry.
v8::Local<v8::Object> GetObjekt() const;
v8::Local<v8::Object> GetRegExp() const;
v8::Local<v8::Object> GetString() const;
private:
ChromeV8Context* context_;
......
......@@ -160,7 +160,7 @@ AdView.prototype.setupAdviewNodeMethods_ = function() {
var self = this;
$Array.forEach(AD_VIEW_API_METHODS, function(apiMethod) {
self.adviewNode_[apiMethod] = function(var_args) {
return self.browserPluginNode_[apiMethod].apply(
return $Function.apply(self.browserPluginNode_[apiMethod],
self.browserPluginNode_, arguments);
};
}, this);
......
......@@ -22,8 +22,8 @@ function wrapForLogging(fun) {
// TODO(ataly): We need to make sure we use the right prototype for
// fun.apply. Array slice can either be rewritten or similarly defined.
logActivity.LogAPICall(id, "app." + fun.name,
Array.prototype.slice.call(arguments));
return fun.apply(this, arguments);
$Array.slice(arguments));
return $Function.apply(fun, this, arguments);
});
}
......
......@@ -27,7 +27,7 @@ eventBindings.registerArgumentMassager('app.runtime.onLaunched',
if (err) {
console.error('Error getting fileEntry, code: ' + err.code);
} else {
items.push(item);
$Array.push(items, item);
}
if (--numItems === 0) {
if (items.length === 0) {
......
......@@ -40,9 +40,9 @@ APIFunctions.prototype.registerUnavailable = function(apiName) {
APIFunctions.prototype.setHook_ =
function(apiName, propertyName, customizedFunction) {
if (this.unavailableApiFunctions_.hasOwnProperty(apiName))
if ($Object.hasOwnProperty(this.unavailableApiFunctions_, apiName))
return;
if (!this.apiFunctions_.hasOwnProperty(apiName))
if (!$Object.hasOwnProperty(this.apiFunctions_, apiName))
throw new Error('Tried to set hook for unknown API "' + apiName + '"');
this.apiFunctions_[apiName][propertyName] = customizedFunction;
};
......@@ -50,15 +50,14 @@ APIFunctions.prototype.setHook_ =
APIFunctions.prototype.setHandleRequest =
function(apiName, customizedFunction) {
var prefix = this.namespace;
// TODO(ataly): Need to replace/redefine apply and slice.
return this.setHook_(apiName, 'handleRequest',
function() {
var ret = customizedFunction.apply(this, arguments);
var ret = $Function.apply(customizedFunction, this, arguments);
// Logs API calls to the Activity Log if it doesn't go through an
// ExtensionFunction.
if (!sendRequestHandler.getCalledSendRequest())
logActivity.LogAPICall(extensionId, prefix + "." + apiName,
Array.prototype.slice.call(arguments));
$Array.slice(arguments));
return ret;
});
};
......@@ -107,7 +106,7 @@ function getPlatform() {
];
for (var i = 0; i < platforms.length; i++) {
if (platforms[i][0].test(navigator.appVersion)) {
if ($RegExp.test(platforms[i][0], navigator.appVersion)) {
return platforms[i][1];
}
}
......@@ -176,7 +175,7 @@ Binding.prototype = {
// interact with, and second the current extension ID. See where
// |customHooks| is used.
registerCustomHook: function(fn) {
this.customHooks_.push(fn);
$Array.push(this.customHooks_, fn);
},
// TODO(kalman/cduvall): Refactor this so |runHooks_| is not needed.
......@@ -207,7 +206,7 @@ Binding.prototype = {
return shouldCheck;
$Array.forEach(['functions', 'events'], function(type) {
if (schema.hasOwnProperty(type)) {
if ($Object.hasOwnProperty(schema, type)) {
$Array.forEach(schema[type], function(node) {
if ('unprivileged' in node)
shouldCheck = true;
......@@ -218,7 +217,7 @@ Binding.prototype = {
return shouldCheck;
for (var property in schema.properties) {
if (schema.hasOwnProperty(property) &&
if ($Object.hasOwnProperty(schema, property) &&
'unprivileged' in schema.properties[property]) {
shouldCheck = true;
break;
......@@ -238,7 +237,7 @@ Binding.prototype = {
var mod = {};
var namespaces = schema.namespace.split('.');
var namespaces = $String.split(schema.namespace, '.');
for (var index = 0, name; name = namespaces[index]; index++) {
mod[name] = mod[name] || {};
mod = mod[name];
......@@ -301,19 +300,22 @@ Binding.prototype = {
this.apiFunctions_.register(functionDef.name, apiFunction);
mod[functionDef.name] = $Function.bind(function() {
var args = Array.prototype.slice.call(arguments);
var args = $Array.slice(arguments);
if (this.updateArgumentsPreValidate)
args = this.updateArgumentsPreValidate.apply(this, args);
args = $Function.apply(this.updateArgumentsPreValidate, this, args);
args = schemaUtils.normalizeArgumentsAndValidate(args, this);
if (this.updateArgumentsPostValidate)
args = this.updateArgumentsPostValidate.apply(this, args);
if (this.updateArgumentsPostValidate) {
args = $Function.apply(this.updateArgumentsPostValidate,
this,
args);
}
sendRequestHandler.clearCalledSendRequest();
var retval;
if (this.handleRequest) {
retval = this.handleRequest.apply(this, args);
retval = $Function.apply(this.handleRequest, this, args);
} else {
var optArgs = {
customCallback: this.customCallback
......@@ -403,7 +405,7 @@ Binding.prototype = {
// not as an array), so we have to fake calling |new| on the
// constructor.
value = { __proto__: constructor.prototype };
constructor.apply(value, args);
$Function.apply(constructor, value, args);
// Recursively add properties.
addProperties(value, propertyDef);
} else if (type === 'object') {
......@@ -421,7 +423,7 @@ Binding.prototype = {
addProperties(mod, schema);
var availability = GetAvailability(schema.namespace);
if (!availability.is_available && Object.keys(mod).length == 0) {
if (!availability.is_available && $Object.keys(mod).length == 0) {
console.error('chrome.' + schema.namespace + ' is not available: ' +
availability.message);
return;
......
......@@ -121,7 +121,7 @@ binding.registerCustomHook(function(api) {
apiFunctions.setUpdateArgumentsPostValidate('getDevices',
function() {
var args = Array.prototype.slice.call(arguments);
var args = $Array.slice(arguments);
if (bluetooth.getDevicesState != null) {
throw new Error('Concurrent calls to getDevices are not allowed.');
......@@ -131,7 +131,7 @@ binding.registerCustomHook(function(api) {
if (typeof(args[args.length - 1]) == 'function') {
state.finalCallback = args.pop();
args.push(
$Array.push(args,
function() {
if (chrome.runtime.lastError) {
finishDeviceSearch();
......
......@@ -7,7 +7,7 @@ var sendRequest = require('sendRequest').sendRequest;
var validate = require('schemaUtils').validate;
function extendSchema(schema) {
var extendedSchema = schema.slice();
var extendedSchema = $Array.slice(schema);
extendedSchema.unshift({'type': 'string'});
return extendedSchema;
}
......@@ -21,7 +21,8 @@ function ChromeSetting(prefKey, valueSchema) {
extendSchema(getSchema));
};
this.set = function(details, callback) {
var setSchema = this.functionSchemas.set.definition.parameters.slice();
var setSchema = $Array.slice(
this.functionSchemas.set.definition.parameters);
setSchema[0].properties.value = valueSchema;
validate([details, callback], setSchema);
return sendRequest('types.ChromeSetting.set',
......
......@@ -8,7 +8,7 @@ var sendRequest = require('sendRequest').sendRequest;
var validate = require('schemaUtils').validate;
function extendSchema(schema) {
var extendedSchema = schema.slice();
var extendedSchema = $Array.slice(schema);
extendedSchema.unshift({'type': 'string'});
return extendedSchema;
}
......@@ -22,7 +22,8 @@ function ContentSetting(contentType, settingSchema) {
extendSchema(getSchema));
};
this.set = function(details, callback) {
var setSchema = this.functionSchemas.set.definition.parameters.slice();
var setSchema = $Array.slice(
this.functionSchemas.set.definition.parameters);
setSchema[0].properties.setting = settingSchema;
validate([details, callback], setSchema);
return sendRequest('contentSettings.set',
......
......@@ -10,7 +10,7 @@ exports.FindMatchingSelectors = function(cssSelectors) {
$Array.forEach(cssSelectors, function(selector, index) {
try {
if (document.querySelector(selector) != null)
result.push(index);
$Array.push(result, index);
} catch (exception) {
throw new Error("query Selector failed on '" + selector + "': " +
exception.stack);
......
......@@ -39,7 +39,7 @@ binding.registerCustomHook(function(bindingsAPI) {
var id = arguments[0].menuItemId;
var onclick = contextMenus.handlersForId(id)[id];
if (onclick) {
onclick.apply(null, arguments);
$Function.apply(onclick, null, arguments);
}
});
};
......
......@@ -26,7 +26,7 @@ binding.registerCustomHook( function(api) {
// generated union dictionary against the schema for |typeId|.
function setupInstance(instance, parameters, typeId) {
for (var key in parameters) {
if (parameters.hasOwnProperty(key)) {
if ($Object.hasOwnProperty(parameters, key)) {
instance[key] = parameters[key];
}
}
......
......@@ -26,7 +26,7 @@ binding.registerCustomHook(function(api) {
// generated union dictionary against the schema for |typeId|.
function setupInstance(instance, parameters, typeId) {
for (var key in parameters) {
if (parameters.hasOwnProperty(key)) {
if ($Object.hasOwnProperty(parameters, key)) {
instance[key] = parameters[key];
}
}
......
......@@ -17,7 +17,7 @@ function computeId(entry) {
if (!fileSystemId)
return null;
// Strip the leading '/' from the path.
return fileSystemId + ':' + entry.fullPath.slice(1);
return fileSystemId + ':' + $String.slice(entry.fullPath, 1);
}
function registerEntry(id, entry) {
......
......@@ -109,14 +109,14 @@
FilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) {
var result = [];
for (var i = 0; i < ids.length; i++)
result.push(this.listenerMap_[ids[i]]);
$Array.push(result, this.listenerMap_[ids[i]]);
return result;
};
function parseEventOptions(opt_eventOptions) {
function merge(dest, src) {
for (var k in src) {
if (!dest.hasOwnProperty(k)) {
if (!$Object.hasOwnProperty(dest, k)) {
dest[k] = src[k];
}
}
......@@ -224,7 +224,7 @@
}
var listener = {callback: cb, filters: filters};
this.attach_(listener);
this.listeners_.push(listener);
$Array.push(this.listeners_, listener);
};
Event.prototype.attach_ = function(listener) {
......@@ -249,7 +249,7 @@
if (idx == -1)
return;
var removedListener = this.listeners_.splice(idx, 1)[0];
var removedListener = $Array.splice(this.listeners_, idx, 1)[0];
this.attachmentStrategy_.onRemovedListener(removedListener);
if (this.listeners_.length == 0) {
......@@ -308,15 +308,15 @@
// Make a copy of the listeners in case the listener list is modified
// while dispatching the event.
var listeners =
this.attachmentStrategy_.getListenersByIDs(listenerIDs).slice();
var listeners = $Array.slice(
this.attachmentStrategy_.getListenersByIDs(listenerIDs));
var results = [];
for (var i = 0; i < listeners.length; i++) {
try {
var result = this.dispatchToListener(listeners[i].callback, args);
if (result !== undefined)
results.push(result);
$Array.push(results, result);
} catch (e) {
var errorMessage = "Error in event handler";
if (this.eventName_)
......@@ -331,13 +331,13 @@
// Can be overridden to support custom dispatching.
Event.prototype.dispatchToListener = function(callback, args) {
return callback.apply(null, args);
return $Function.apply(callback, null, args);
}
// Dispatches this event object to all listeners, passing all supplied
// arguments to this function each listener.
Event.prototype.dispatch = function(varargs) {
return this.dispatch_(Array.prototype.slice.call(arguments), undefined);
return this.dispatch_($Array.slice(arguments), undefined);
};
// Detaches this event object from its name.
......@@ -396,7 +396,8 @@
// We remove the first parameter from the validation to give the user more
// meaningful error messages.
validate([rules, opt_cb],
ruleFunctionSchemas.addRules.parameters.slice().splice(1));
$Array.splice(
$Array.slice(ruleFunctionSchemas.addRules.parameters), 1));
sendRequest("events.addRules", [this.eventName_, rules, opt_cb],
ruleFunctionSchemas.addRules.parameters);
}
......@@ -408,7 +409,8 @@
// We remove the first parameter from the validation to give the user more
// meaningful error messages.
validate([ruleIdentifiers, opt_cb],
ruleFunctionSchemas.removeRules.parameters.slice().splice(1));
$Array.splice(
$Array.slice(ruleFunctionSchemas.removeRules.parameters), 1));
sendRequest("events.removeRules",
[this.eventName_, ruleIdentifiers, opt_cb],
ruleFunctionSchemas.removeRules.parameters);
......@@ -421,7 +423,8 @@
// We remove the first parameter from the validation to give the user more
// meaningful error messages.
validate([ruleIdentifiers, cb],
ruleFunctionSchemas.getRules.parameters.slice().splice(1));
$Array.splice(
$Array.slice(ruleFunctionSchemas.getRules.parameters), 1));
sendRequest("events.getRules",
[this.eventName_, ruleIdentifiers, cb],
......
......@@ -45,8 +45,10 @@ binding.registerCustomHook(
// We are making a copy of |arr|, but applying |func| to index 1.
function validate(arr, func) {
var newArr = [];
for (var i = 0; i < arr.length; i++)
newArr.push(i == 1 && typeof(arr) == 'object' ? func(arr[i]) : arr[i]);
for (var i = 0; i < arr.length; i++) {
$Array.push(newArr,
i == 1 && typeof(arr) == 'object' ? func(arr[i]) : arr[i]);
}
return newArr;
}
......
......@@ -80,7 +80,7 @@ binding.registerCustomHook(function(bindingsAPI, extensionId) {
// Checking existence isn't enough since some functions are disabled via
// getters that throw exceptions. Assume that any getter is such a function.
if (chrome.runtime &&
chrome.runtime.hasOwnProperty(alias) &&
$Object.hasOwnProperty(chrome.runtime, alias) &&
chrome.runtime.__lookupGetter__(alias) === undefined) {
extension[alias] = chrome.runtime[alias];
}
......
......@@ -76,7 +76,7 @@ binding.registerCustomHook(function(bindingsAPI) {
apiFunctions.setUpdateArgumentsPostValidate(
functionName, function(fileEntry, callback) {
var fileSystemName = fileEntry.filesystem.name;
var relativePath = fileEntry.fullPath.slice(1);
var relativePath = $String.slice(fileEntry.fullPath, 1);
return [fileSystemName, relativePath, callback];
});
}
......@@ -93,7 +93,7 @@ binding.registerCustomHook(function(bindingsAPI) {
if (!id)
return '';
var fileSystemName = fileEntry.filesystem.name;
var relativePath = fileEntry.fullPath.slice(1);
var relativePath = $String.slice(fileEntry.fullPath, 1);
sendRequest(this.name, [id, fileSystemName, relativePath],
this.definition.parameters, {});
......@@ -129,19 +129,19 @@ binding.registerCustomHook(function(bindingsAPI) {
fileSystem.getWritableFileEntry = function() {
console.log("chrome.fileSystem.getWritableFileEntry is deprecated");
console.log("Please use chrome.fileSystem.getWritableEntry instead");
fileSystem.getWritableEntry.apply(this, arguments);
$Function.apply(fileSystem.getWritableEntry, this, arguments);
};
fileSystem.isWritableFileEntry = function() {
console.log("chrome.fileSystem.isWritableFileEntry is deprecated");
console.log("Please use chrome.fileSystem.isWritableEntry instead");
fileSystem.isWritableEntry.apply(this, arguments);
$Function.apply(fileSystem.isWritableEntry, this, arguments);
};
fileSystem.chooseFile = function() {
console.log("chrome.fileSystem.chooseFile is deprecated");
console.log("Please use chrome.fileSystem.chooseEntry instead");
fileSystem.chooseEntry.apply(this, arguments);
$Function.apply(fileSystem.chooseEntry, this, arguments);
};
});
......
......@@ -13,7 +13,7 @@ binding.registerCustomHook(function(bindingsAPI, extensionId) {
var apiFunctions = bindingsAPI.apiFunctions;
apiFunctions.setUpdateArgumentsPreValidate('getMessage', function() {
var args = Array.prototype.slice.call(arguments);
var args = $Array.slice(arguments);
// The first argument is the message, and should be a string.
var message = args[0];
......
......@@ -60,7 +60,7 @@ function on_complete_index(index, err, loading, finished, callbacks) {
finished[index] = { width: width, height: height, data: imageData };
if (err)
callbacks.onerror(index);
if (Object.keys(loading).length == 0)
if ($Object.keys(loading).length == 0)
callbacks.oncomplete(finished);
}
}
......
......@@ -167,18 +167,18 @@ JSONSchemaValidator.prototype.addTypes = function(typeOrTypeList) {
JSONSchemaValidator.prototype.getAllTypesForSchema = function(schema) {
var schemaTypes = [];
if (schema.type)
schemaTypes.push(schema.type);
$Array.push(schemaTypes, schema.type);
if (schema.choices) {
for (var i = 0; i < schema.choices.length; i++) {
var choiceTypes = this.getAllTypesForSchema(schema.choices[i]);
schemaTypes = schemaTypes.concat(choiceTypes);
schemaTypes = $Array.concat(schemaTypes, choiceTypes);
}
}
var ref = schema['$ref'];
if (ref) {
var type = this.getOrAddType(ref);
CHECK(type, 'Could not find type ' + ref);
schemaTypes = schemaTypes.concat(this.getAllTypesForSchema(type));
schemaTypes = $Array.concat(schemaTypes, this.getAllTypesForSchema(type));
}
return schemaTypes;
};
......@@ -341,7 +341,7 @@ JSONSchemaValidator.prototype.validateObject =
// TODO(aa): If it ever turns out that we actually want this to work,
// there are other checks we could put here, like requiring that schema
// properties be objects that have a 'type' property.
if (!schema.properties.hasOwnProperty(prop))
if (!$Object.hasOwnProperty(schema.properties, prop))
continue;
var propPath = path ? path + "." + prop : prop;
......@@ -377,7 +377,7 @@ JSONSchemaValidator.prototype.validateObject =
continue;
// Any properties inherited through the prototype are ignored.
if (!instance.hasOwnProperty(prop))
if (!$Object.hasOwnProperty(instance, prop))
continue;
var propPath = path ? path + "." + prop : prop;
......@@ -502,7 +502,7 @@ JSONSchemaValidator.prototype.validateType = function(instance, schema, path) {
* message.
*/
JSONSchemaValidator.prototype.addError = function(path, key, replacements) {
this.errors.push({
$Array.push(this.errors, {
path: path,
message: JSONSchemaValidator.formatError(key, replacements)
});
......
......@@ -54,7 +54,7 @@ function run(name, message, stack, callback, args) {
var targetChrome = GetGlobal(callback).chrome;
set(name, message, stack, targetChrome);
try {
callback.apply(undefined, args);
$Function.apply(callback, undefined, args);
} finally {
clear(targetChrome);
}
......
......@@ -24,7 +24,7 @@ binding.registerCustomHook(function(bindingsAPI, extensionId) {
for (var i = 0; i < response.length; i++) {
var filesystem = mediaGalleriesNatives.GetMediaFileSystemObject(
response[i].fsid);
result.push(filesystem);
$Array.push(result, filesystem);
var metadata = response[i];
delete metadata.fsid;
mediaGalleriesMetadata[filesystem.name] = metadata;
......
......@@ -101,19 +101,19 @@
var errorMsg = [];
var eventName = isSendMessage ? "runtime.onMessage" : "extension.onRequest";
if (isSendMessage && !responseCallbackPreserved) {
errorMsg.push(
$Array.push(errorMsg,
"The chrome." + eventName + " listener must return true if you " +
"want to send a response after the listener returns");
} else {
errorMsg.push(
$Array.push(errorMsg,
"Cannot send a response more than once per chrome." + eventName +
" listener per document");
}
errorMsg.push("(message was sent by extension" + sourceExtensionId);
$Array.push(errorMsg, "(message was sent by extension" + sourceExtensionId);
if (sourceExtensionId != "" && sourceExtensionId != targetExtensionId)
errorMsg.push("for extension " + targetExtensionId);
$Array.push(errorMsg, "for extension " + targetExtensionId);
if (sourceUrl != "")
errorMsg.push("for URL " + sourceUrl);
$Array.push(errorMsg, "for URL " + sourceUrl);
lastError.set(eventName, errorMsg.join(" ") + ").", null, chrome);
}
......@@ -318,7 +318,7 @@
// schema validation is expecting, e.g.
// extension.sendRequest(req) -> extension.sendRequest(null, req)
// extension.sendRequest(req, cb) -> extension.sendRequest(null, req, cb)
var args = Array.prototype.splice.call(arguments, 1); // skip functionName
var args = $Array.splice(arguments, 1); // skip functionName
var lastArg = args.length - 1;
// responseCallback (last argument) is optional.
......
......@@ -36,7 +36,7 @@ function replaceNotificationOptionURLs(notification_details, callback) {
// |imageUrl| is optional.
if (notification_details.imageUrl) {
url_specs.push({
$Array.push(url_specs, {
path: notification_details.imageUrl,
width: 360,
height: 540,
......@@ -50,7 +50,7 @@ function replaceNotificationOptionURLs(notification_details, callback) {
var num_buttons = button_list.length;
for (var i = 0; i < num_buttons; i++) {
if (button_list[i].iconUrl) {
url_specs.push({
$Array.push(url_specs, {
path: button_list[i].iconUrl,
width: 16,
height: 16,
......
......@@ -65,7 +65,7 @@ function parseOmniboxDescription(input) {
'type': child.nodeName,
'offset': result.description.length
};
result.descriptionStyles.push(style);
$Array.push(result.descriptionStyles, style);
walk(child);
style.length = result.description.length - style.offset;
continue;
......@@ -105,7 +105,7 @@ binding.registerCustomHook(function(bindingsAPI) {
var parseResult = parseOmniboxDescription(
userSuggestions[i].description);
parseResult.content = userSuggestions[i].content;
suggestions.push(parseResult);
$Array.push(suggestions, parseResult);
}
return [requestId, suggestions];
});
......
......@@ -21,7 +21,7 @@ binding.registerCustomHook(function(api) {
var permissions = api.compiledApi;
function maybeConvertToObject(str) {
var parts = str.split('|');
var parts = $String.split(str, '|');
if (parts.length != 2)
return str;
......@@ -41,7 +41,7 @@ binding.registerCustomHook(function(api) {
for (var i = 0; i < args.length; i += 1) {
if (typeof(args[i]) == 'object') {
var a = args[i];
var keys = Object.keys(a);
var keys = $Object.keys(a);
if (keys.length != 1) {
throw new Error("Too many keys in object-style permission.");
}
......@@ -75,7 +75,7 @@ binding.registerCustomHook(function(api) {
// that handleResponse doesn't call it again.
try {
if (request.callback)
request.callback.apply(request, [response]);
$Function.apply(request.callback, request, [response]);
} finally {
delete request.callback;
}
......
......@@ -134,5 +134,5 @@ Window.prototype.addEventListener = function(type) {
if (type === 'unload' || type === 'beforeunload')
generateDisabledMethodStub(type)();
else
return windowAddEventListener.apply(window, arguments);
return $Function.apply(windowAddEventListener, window, arguments);
};
......@@ -44,11 +44,11 @@ function getSignatures(parameterSchemas) {
if (parameterSchemas.length === 0)
return [[]];
var signatures = [];
var remaining = getSignatures(parameterSchemas.slice(1));
var remaining = getSignatures($Array.slice(parameterSchemas, 1));
for (var i = 0; i < remaining.length; i++)
signatures.push([parameterSchemas[0]].concat(remaining[i]))
$Array.push(signatures, $Array.concat([parameterSchemas[0]], remaining[i]))
if (parameterSchemas[0].optional)
return signatures.concat(remaining);
return $Array.concat(signatures, remaining);
return signatures;
};
......@@ -119,9 +119,9 @@ function normalizeArgumentsAndValidate(args, funDef) {
var ai = 0;
for (var si = 0; si < definedSignature.length; si++) {
if (definedSignature[si] === resolvedSignature[ai])
normalizedArgs.push(args[ai++]);
$Array.push(normalizedArgs, args[ai++]);
else
normalizedArgs.push(null);
$Array.push(normalizedArgs, null);
}
return normalizedArgs;
};
......
......@@ -100,7 +100,7 @@ if (!chrome.embeddedSearch) {
}
var dedupedResults = [];
for (url in urlToResultMap) {
dedupedResults.push(urlToResultMap[url]);
$Array.push(dedupedResults, urlToResultMap[url]);
}
return dedupedResults;
}
......
......@@ -18,7 +18,7 @@ var calledSendRequest = false;
// Runs a user-supplied callback safely.
function safeCallbackApply(name, request, callback, args) {
try {
callback.apply(request, args);
$Function.apply(callback, request, args);
} catch (e) {
var errorMessage = "Error in response to " + name + ": " + e;
if (request.stack && request.stack != '')
......@@ -44,7 +44,7 @@ function handleResponse(requestId, name, success, responseList, error) {
if (request.callback) {
var chromeForCallback = natives.GetGlobal(request.callback).chrome;
if (chromeForCallback != chrome)
chromesForLastError.push(chromeForCallback);
$Array.push(chromesForLastError, chromeForCallback);
}
$Array.forEach(chromesForLastError, function(c) {lastError.clear(c)});
......@@ -60,7 +60,7 @@ function handleResponse(requestId, name, success, responseList, error) {
safeCallbackApply(name,
request,
request.customCallback,
[name, request].concat(responseList));
$Array.concat([name, request], responseList));
}
if (request.callback) {
......@@ -82,7 +82,7 @@ function handleResponse(requestId, name, success, responseList, error) {
};
function getExtensionStackTrace(call_name) {
var stack = new Error().stack.split('\n');
var stack = $String.split(new Error().stack, '\n');
// Remove stack frames before and after that weren't associated with the
// extension.
......
......@@ -7,7 +7,7 @@ var normalizeArgumentsAndValidate =
var sendRequest = require('sendRequest').sendRequest;
function extendSchema(schema) {
var extendedSchema = schema.slice();
var extendedSchema = $Array.slice(schema);
extendedSchema.unshift({'type': 'string'});
return extendedSchema;
}
......@@ -24,11 +24,11 @@ function StorageArea(namespace, schema) {
function bindApiFunction(functionName) {
self[functionName] = function() {
var funSchema = this.functionSchemas[functionName];
var args = Array.prototype.slice.call(arguments);
var args = $Array.slice(arguments);
args = normalizeArgumentsAndValidate(args, funSchema);
return sendRequest(
'storage.' + functionName,
[namespace].concat(args),
$Array.concat([namespace], args),
extendSchema(funSchema.definition.parameters),
{preserveNullInObjects: true});
};
......
......@@ -29,7 +29,7 @@ binding.registerCustomHook(function(bindingsAPI) {
functionName, function(entries, callback) {
var fileSystemUrlArray = [];
for (var i=0; i < entries.length; i++) {
fileSystemUrlArray.push(entries[i].toURL());
$Array.push(fileSystemUrlArray, entries[i].toURL());
}
return [fileSystemUrlArray, callback];
});
......@@ -76,7 +76,7 @@ binding.registerCustomHook(function(bindingsAPI) {
entry.isDirectory);
result.status = response[i].status;
result.error = response[i].error;
results.push(result);
$Array.push(results, result);
}
}
if (request.callback)
......
......@@ -61,8 +61,10 @@ binding.registerCustomHook(function(api) {
var redundantPrefix = 'Error\n';
chrome.test.fail(
'Callback has already been run. ' +
'First call:\n' + called.slice(redundantPrefix.length) + '\n' +
'Second call:\n' + new Error().stack.slice(redundantPrefix.length));
'First call:\n' +
$String.slice(called, redundantPrefix.length) + '\n' +
'Second call:\n' +
$String.slice(new Error().stack, redundantPrefix.length));
}
called = new Error().stack;
......@@ -151,12 +153,16 @@ binding.registerCustomHook(function(api) {
return false;
for (var p in actual) {
if (actual.hasOwnProperty(p) && !expected.hasOwnProperty(p))
if ($Object.hasOwnProperty(actual, p) &&
!$Object.hasOwnProperty(expected, p)) {
return false;
}
}
for (var p in expected) {
if (expected.hasOwnProperty(p) && !actual.hasOwnProperty(p))
if ($Object.hasOwnProperty(expected, p) &&
!$Object.hasOwnProperty(actual, p)) {
return false;
}
}
for (var p in expected) {
......@@ -225,7 +231,7 @@ binding.registerCustomHook(function(api) {
function safeFunctionApply(func, args) {
try {
if (func)
func.apply(null, args);
$Function.apply(func, null, args);
} catch (e) {
var msg = "uncaught exception " + e;
chromeTest.fail(msg);
......
......@@ -11,13 +11,13 @@
var listeners = [];
exports.addListener = function(listener) {
listeners.push(listener);
$Array.push(listeners, listener);
};
exports.removeListener = function(listener) {
for (var i = 0; i < listeners.length; ++i) {
if (listeners[i] == listener) {
listeners.splice(i, 1);
$Array.splice(listeners, i, 1);
return;
}
}
......
......@@ -32,7 +32,7 @@ function lookup(array_of_dictionaries, field, value) {
}
function loadTypeSchema(typeName, defaultSchema) {
var parts = typeName.split('.');
var parts = $String.split(typeName, '.');
if (parts.length == 1) {
if (defaultSchema == null) {
WARNING('Trying to reference "' + typeName + '" ' +
......@@ -41,7 +41,7 @@ function loadTypeSchema(typeName, defaultSchema) {
}
var types = defaultSchema.types;
} else {
var schemaName = parts.slice(0, parts.length - 1).join('.')
var schemaName = $Array.join($Array.slice(parts, 0, parts.length - 1), '.');
var types = schemaRegistry.GetSchema(schemaName).types;
}
for (var i = 0; i < types.length; ++i) {
......
......@@ -12,7 +12,7 @@ binding.registerCustomHook(function(api) {
var apiFunctions = api.apiFunctions;
apiFunctions.setHandleRequest('handlerBehaviorChanged', function() {
var args = Array.prototype.slice.call(arguments);
var args = $Array.slice(arguments);
sendRequest(this.name, args, this.definition.parameters,
{forIOThread: true});
});
......
......@@ -67,7 +67,7 @@ WebRequestEvent.prototype.addListener =
var subEventName = webRequestNatives.GetUniqueSubEventName(this.eventName_);
// Note: this could fail to validate, in which case we would not add the
// subEvent listener.
validate(Array.prototype.slice.call(arguments, 1), this.extraArgSchemas_);
validate($Array.slice(arguments, 1), this.extraArgSchemas_);
webRequestInternal.addEventListener(
cb, opt_filter, opt_extraInfo, this.eventName_, subEventName,
this.webViewInstanceId_);
......@@ -79,7 +79,7 @@ WebRequestEvent.prototype.addListener =
subEventCallback = function() {
var requestId = arguments[0].requestId;
try {
var result = cb.apply(null, arguments);
var result = $Function.apply(cb, null, arguments);
webRequestInternal.eventHandled(
eventName, subEventName, requestId, result);
} catch (e) {
......@@ -97,10 +97,10 @@ WebRequestEvent.prototype.addListener =
webRequestInternal.eventHandled(
eventName, subEventName, requestId, response);
};
cb.apply(null, [details, handledCallback]);
$Function.apply(cb, null, [details, handledCallback]);
};
}
this.subEvents_.push(
$Array.push(this.subEvents_,
{subEvent: subEvent, callback: cb, subEventCallback: subEventCallback});
subEvent.addListener(subEventCallback);
};
......@@ -117,7 +117,7 @@ WebRequestEvent.prototype.removeListener = function(cb) {
console.error(
'Internal error: webRequest subEvent has orphaned listeners.');
}
this.subEvents_.splice(idx, 1);
$Array.splice(this.subEvents_, idx, 1);
}
};
......@@ -156,13 +156,13 @@ binding.registerCustomHook(function(api) {
var apiFunctions = api.apiFunctions;
apiFunctions.setHandleRequest('addEventListener', function() {
var args = Array.prototype.slice.call(arguments);
var args = $Array.slice(arguments);
sendRequest(this.name, args, this.definition.parameters,
{forIOThread: true});
});
apiFunctions.setHandleRequest('eventHandled', function() {
var args = Array.prototype.slice.call(arguments);
var args = $Array.slice(arguments);
sendRequest(this.name, args, this.definition.parameters,
{forIOThread: true});
});
......
......@@ -138,7 +138,7 @@ WebView.prototype.setupWebviewNodeMethods_ = function() {
var self = this;
$Array.forEach(WEB_VIEW_API_METHODS, function(apiMethod) {
self.webviewNode_[apiMethod] = function(var_args) {
return self.browserPluginNode_[apiMethod].apply(
return $Function.apply(self.browserPluginNode_[apiMethod],
self.browserPluginNode_, arguments);
};
}, this);
......@@ -388,15 +388,15 @@ WebView.prototype.setupExecuteCodeAPI_ = function() {
this.webviewNode_['executeScript'] = function(var_args) {
validateCall();
var args = [self.browserPluginNode_.getGuestInstanceId()].concat(
Array.prototype.slice.call(arguments));
chrome.webview.executeScript.apply(null, args);
var args = $Array.concat([self.browserPluginNode_.getGuestInstanceId()],
$Array.slice(arguments));
$Function.apply(chrome.webview.executeScript, null, args);
}
this.webviewNode_['insertCSS'] = function(var_args) {
validateCall();
var args = [self.browserPluginNode_.getGuestInstanceId()].concat(
Array.prototype.slice.call(arguments));
chrome.webview.insertCSS.apply(null, args);
var args = $Array.concat([self.browserPluginNode_.getGuestInstanceId()],
$Array.slice(arguments));
$Function.apply(chrome.webview.insertCSS, null, args);
}
};
......
......@@ -4,6 +4,62 @@
window.assertions = (function() {
// We are going to kill all of the builtins, so hold onto the ones we need.
var defineGetter = Object.prototype.__defineGetter__;
var defineSetter = Object.prototype.__defineSetter__;
var Error = window.Error;
var forEach = Array.prototype.forEach;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var getOwnPropertyNames = Object.getOwnPropertyNames;
var stringify = JSON.stringify;
// Kill all of the builtins functions to give us a fairly high confidence that
// the environment our bindings run in can't interfere with our code.
// These are taken from the ECMAScript spec.
var builtinTypes = [
Object, Function, Array, String, Boolean, Number, Math, Date, RegExp, JSON,
];
function clobber(obj, name, qualifiedName) {
// Clobbering constructors would break everything.
// Clobbering toString is annoying.
// Clobbering __proto__ breaks in ways that grep can't find.
// Clobbering Function.call would make it impossible to implement these tests.
// Clobbering Object.valueOf breaks v8.
if (name == 'constructor' ||
name == 'toString' ||
name == '__proto__' ||
qualifiedName == 'Function.call' ||
qualifiedName == 'Object.valueOf') {
return;
}
if (typeof(obj[name]) == 'function') {
obj[name] = function() {
throw new Error('Clobbered ' + qualifiedName + ' function');
};
} else {
defineGetter.call(obj, name, function() {
throw new Error('Clobbered ' + qualifiedName + ' getter');
});
}
}
forEach.call(builtinTypes, function(builtin) {
var prototype = builtin.prototype;
var typename = '<unknown>';
if (prototype) {
typename = prototype.constructor.name;
forEach.call(getOwnPropertyNames(prototype), function(name) {
clobber(prototype, name, typename + '.' + name);
});
}
forEach.call(getOwnPropertyNames(builtin), function(name) {
clobber(builtin, name, typename + '.' + name);
});
if (builtin.name)
clobber(window, builtin.name, 'window.' + builtin.name);
});
// Codes for test results. Must match ExternallyConnectableMessagingTest::Result
// in c/b/extensions/extension_messages_apitest.cc.
var results = {
......@@ -37,7 +93,7 @@ function checkResponse(response, reply) {
//
// First check the sender was correct.
var incorrectSender = false;
if (!response.sender.hasOwnProperty('tab')) {
if (!hasOwnProperty.call(response.sender, 'tab')) {
console.warn('Expected a tab, got none');
incorrectSender = true;
}
......@@ -46,7 +102,7 @@ function checkResponse(response, reply) {
response.sender.tab.url);
incorrectSender = true;
}
if (response.sender.hasOwnProperty('id')) {
if (hasOwnProperty.call(response.sender, 'id')) {
console.warn('Expected no id, got "' + response.sender.id + '"');
incorrectSender = true;
}
......@@ -61,8 +117,8 @@ function checkResponse(response, reply) {
}
// Check the correct content was echoed.
var expectedJson = JSON.stringify(message);
var actualJson = JSON.stringify(response.message);
var expectedJson = stringify(message);
var actualJson = stringify(response.message);
if (actualJson == expectedJson)
return true;
console.warn('Expected message ' + expectedJson + ' got ' + actualJson);
......@@ -70,7 +126,9 @@ function checkResponse(response, reply) {
return false;
}
var sendToBrowser = domAutomationController.send.bind(domAutomationController);
function sendToBrowser(msg) {
domAutomationController.send(msg);
}
return {
canConnectAndSendMessages: function(extensionId) {
......@@ -120,7 +178,7 @@ return {
areAnyRuntimePropertiesDefined: function(names) {
var result = false;
if (chrome.runtime) {
names.forEach(function(name) {
forEach.call(names, function(name) {
if (chrome.runtime[name]) {
console.log('runtime.' + name + ' is defined');
result = true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment