Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(815)

Side by Side Diff: chrome/renderer/resources/extensions/binding.js

Issue 12647017: Lazily require types when validating Extensions API calls (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixes Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 require('json_schema'); 5 require('json_schema');
6 require('event_bindings'); 6 require('event_bindings');
7 var chrome = requireNative('chrome').GetChrome(); 7 var chrome = requireNative('chrome').GetChrome();
8 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); 8 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
9 var forEach = require('utils').forEach; 9 var forEach = require('utils').forEach;
10 var GetAvailability = requireNative('v8_context').GetAvailability; 10 var GetAvailability = requireNative('v8_context').GetAvailability;
11 var logging = requireNative('logging'); 11 var logging = requireNative('logging');
12 var process = requireNative('process'); 12 var process = requireNative('process');
13 var contextType = process.GetContextType(); 13 var contextType = process.GetContextType();
14 var extensionId = process.GetExtensionId(); 14 var extensionId = process.GetExtensionId();
15 var manifestVersion = process.GetManifestVersion(); 15 var manifestVersion = process.GetManifestVersion();
16 var schemaRegistry = requireNative('schema_registry'); 16 var schemaRegistry = requireNative('schema_registry');
17 var schemaUtils = require('schemaUtils'); 17 var schemaUtils = require('schemaUtils');
18 var sendRequest = require('sendRequest').sendRequest; 18 var sendRequest = require('sendRequest').sendRequest;
19 var utils = require('utils'); 19 var utils = require('utils');
20 var CHECK = requireNative('logging').CHECK;
20 21
21 // Stores the name and definition of each API function, with methods to 22 // Stores the name and definition of each API function, with methods to
22 // modify their behaviour (such as a custom way to handle requests to the 23 // modify their behaviour (such as a custom way to handle requests to the
23 // API, a custom callback, etc). 24 // API, a custom callback, etc).
24 function APIFunctions() { 25 function APIFunctions() {
25 this.apiFunctions_ = {}; 26 this.apiFunctions_ = {};
26 this.unavailableApiFunctions_ = {}; 27 this.unavailableApiFunctions_ = {};
27 } 28 }
28 29
29 APIFunctions.prototype.register = function(apiName, apiFunction) { 30 APIFunctions.prototype.register = function(apiName, apiFunction) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 function isManifestVersionSupported(schemaNode, manifestVersion) { 111 function isManifestVersionSupported(schemaNode, manifestVersion) {
111 return !schemaNode.maximumManifestVersion || 112 return !schemaNode.maximumManifestVersion ||
112 manifestVersion <= schemaNode.maximumManifestVersion; 113 manifestVersion <= schemaNode.maximumManifestVersion;
113 } 114 }
114 115
115 function isSchemaNodeSupported(schemaNode, platform, manifestVersion) { 116 function isSchemaNodeSupported(schemaNode, platform, manifestVersion) {
116 return isPlatformSupported(schemaNode, platform) && 117 return isPlatformSupported(schemaNode, platform) &&
117 isManifestVersionSupported(schemaNode, manifestVersion); 118 isManifestVersionSupported(schemaNode, manifestVersion);
118 } 119 }
119 120
121 function createCustomType(type) {
122 var jsModule = type.js_module;
123 CHECK(jsModule, 'Custom type has no "js_module" property.');
not at google - send to devlin 2013/03/21 01:36:55 'custom type ' + type.id + ' must have a...'
cduvall 2013/03/21 17:16:07 Done.
124 var customType = require(jsModule)[jsModule];
not at google - send to devlin 2013/03/21 01:36:55 i don't really know how paranoid we should be here
cduvall 2013/03/21 17:16:07 Done.
125 customType.prototype = new CustomBindingsObject();
126 customType.prototype.setSchema(type);
127 return customType;
128 }
129
120 var platform = getPlatform(); 130 var platform = getPlatform();
121 131
122 function Binding(schema) { 132 function Binding(schema) {
123 this.schema_ = schema; 133 this.schema_ = schema;
124 this.apiFunctions_ = new APIFunctions(); 134 this.apiFunctions_ = new APIFunctions();
125 this.customEvent_ = null; 135 this.customEvent_ = null;
126 this.customTypes_ = {};
127 this.customHooks_ = []; 136 this.customHooks_ = [];
128 }; 137 };
129 138
130 Binding.create = function(apiName) { 139 Binding.create = function(apiName) {
131 return new Binding(schemaRegistry.GetSchema(apiName)); 140 return new Binding(schemaRegistry.GetSchema(apiName));
132 }; 141 };
133 142
134 Binding.prototype = { 143 Binding.prototype = {
135 // The API through which the ${api_name}_custom_bindings.js files customize 144 // The API through which the ${api_name}_custom_bindings.js files customize
136 // their API bindings beyond what can be generated. 145 // their API bindings beyond what can be generated.
137 // 146 //
138 // There are 2 types of customizations available: those which are required in 147 // There are 2 types of customizations available: those which are required in
139 // order to do the schema generation (registerCustomEvent and 148 // order to do the schema generation (registerCustomEvent and
140 // registerCustomType), and those which can only run after the bindings have 149 // registerCustomType), and those which can only run after the bindings have
141 // been generated (registerCustomHook). 150 // been generated (registerCustomHook).
142 //
143
144 // Registers a custom type referenced via "$ref" fields in the API schema
145 // JSON.
146 registerCustomType: function(typeName, customTypeFactory) {
147 var customType = customTypeFactory();
148 customType.prototype = new CustomBindingsObject();
149 this.customTypes_[typeName] = customType;
150 },
151 151
152 // Registers a custom event type for the API identified by |namespace|. 152 // Registers a custom event type for the API identified by |namespace|.
153 // |event| is the event's constructor. 153 // |event| is the event's constructor.
154 registerCustomEvent: function(event) { 154 registerCustomEvent: function(event) {
155 this.customEvent_ = event; 155 this.customEvent_ = event;
156 }, 156 },
157 157
158 // Registers a function |hook| to run after the schema for all APIs has been 158 // Registers a function |hook| to run after the schema for all APIs has been
159 // generated. The hook is passed as its first argument an "API" object to 159 // generated. The hook is passed as its first argument an "API" object to
160 // interact with, and second the current extension ID. See where 160 // interact with, and second the current extension ID. See where
(...skipping 16 matching lines...) Expand all
177 schema: this.schema_, 177 schema: this.schema_,
178 compiledApi: api 178 compiledApi: api
179 }, extensionId, contextType); 179 }, extensionId, contextType);
180 }, this); 180 }, this);
181 }, 181 },
182 182
183 // Generates the bindings from |this.schema_| and integrates any custom 183 // Generates the bindings from |this.schema_| and integrates any custom
184 // bindings that might be present. 184 // bindings that might be present.
185 generate: function() { 185 generate: function() {
186 var schema = this.schema_; 186 var schema = this.schema_;
187 var customTypes = this.customTypes_;
188 187
189 // TODO(kalman/cduvall): Make GetAvailability handle this, then delete the 188 // TODO(kalman/cduvall): Make GetAvailability handle this, then delete the
190 // supporting code. 189 // supporting code.
191 if (!isSchemaNodeSupported(schema, platform, manifestVersion)) { 190 if (!isSchemaNodeSupported(schema, platform, manifestVersion)) {
192 console.error('chrome.' + schema.namespace + ' is not supported on ' + 191 console.error('chrome.' + schema.namespace + ' is not supported on ' +
193 'this platform or manifest version'); 192 'this platform or manifest version');
194 return undefined; 193 return undefined;
195 } 194 }
196 195
197 var availability = GetAvailability(schema.namespace); 196 var availability = GetAvailability(schema.namespace);
198 if (!availability.is_available) { 197 if (!availability.is_available) {
199 console.error('chrome.' + schema.namespace + ' is not available: ' + 198 console.error('chrome.' + schema.namespace + ' is not available: ' +
200 availability.message); 199 availability.message);
201 return undefined; 200 return undefined;
202 } 201 }
203 202
204 // See comment on internalAPIs at the top. 203 // See comment on internalAPIs at the top.
205 var mod = {}; 204 var mod = {};
206 205
207 var namespaces = schema.namespace.split('.'); 206 var namespaces = schema.namespace.split('.');
208 for (var index = 0, name; name = namespaces[index]; index++) { 207 for (var index = 0, name; name = namespaces[index]; index++) {
209 mod[name] = mod[name] || {}; 208 mod[name] = mod[name] || {};
210 mod = mod[name]; 209 mod = mod[name];
211 } 210 }
212 211
213 // Add types to global schemaValidator 212 // Add types to global schemaValidator, the ones for the types we depend on
213 // will be added as needed.
214 if (schema.types) { 214 if (schema.types) {
215 forEach(schema.types, function(i, t) { 215 forEach(schema.types, function(i, t) {
216 if (!isSchemaNodeSupported(t, platform, manifestVersion)) 216 if (!isSchemaNodeSupported(t, platform, manifestVersion))
217 return; 217 return;
218 218
219 schemaUtils.schemaValidator.addTypes(t); 219 schemaUtils.schemaValidator.addTypes(t);
220 if (t.type == 'object' && this.customTypes_[t.id]) {
221 var parts = t.id.split(".");
222 this.customTypes_[t.id].prototype.setSchema(t);
223 mod[parts[parts.length - 1]] = this.customTypes_[t.id];
224 }
225 }, this); 220 }, this);
226 } 221 }
227 222
228 // Returns whether access to the content of a schema should be denied, 223 // Returns whether access to the content of a schema should be denied,
229 // based on the presence of "unprivileged" and whether this is an 224 // based on the presence of "unprivileged" and whether this is an
230 // extension process (versus e.g. a content script). 225 // extension process (versus e.g. a content script).
231 function isSchemaAccessAllowed(itemSchema) { 226 function isSchemaAccessAllowed(itemSchema) {
232 return (contextType == 'BLESSED_EXTENSION') || 227 return (contextType == 'BLESSED_EXTENSION') ||
233 schema.unprivileged || 228 schema.unprivileged ||
234 itemSchema.unprivileged; 229 itemSchema.unprivileged;
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 // Values may just have raw types as defined in the JSON, such 359 // Values may just have raw types as defined in the JSON, such
365 // as "WINDOW_ID_NONE": { "value": -1 }. We handle this here. 360 // as "WINDOW_ID_NONE": { "value": -1 }. We handle this here.
366 // TODO(kalman): enforce that things with a "value" property can't 361 // TODO(kalman): enforce that things with a "value" property can't
367 // define their own types. 362 // define their own types.
368 var type = propertyDef.type || typeof(value); 363 var type = propertyDef.type || typeof(value);
369 if (type === 'integer' || type === 'number') { 364 if (type === 'integer' || type === 'number') {
370 value = parseInt(value); 365 value = parseInt(value);
371 } else if (type === 'boolean') { 366 } else if (type === 'boolean') {
372 value = value === 'true'; 367 value = value === 'true';
373 } else if (propertyDef['$ref']) { 368 } else if (propertyDef['$ref']) {
374 if (propertyDef['$ref'] in customTypes) { 369 var constructor = null;
375 var constructor = customTypes[propertyDef['$ref']]; 370 var type = utils.loadTypeSchema(propertyDef['$ref'], schema);
376 } else { 371 if (type)
377 var refParts = propertyDef['$ref'].split('.'); 372 constructor = createCustomType(type);
not at google - send to devlin 2013/03/21 01:36:55 looks like it's actually impossible for createCust
cduvall 2013/03/21 17:16:07 Done.
378 // This should never try to load a $ref in the current namespace.
379 var constructor = utils.loadRefDependency(
380 propertyDef['$ref'])[refParts[refParts.length - 1]];
381 }
382 if (!constructor) 373 if (!constructor)
383 throw new Error('No custom binding for ' + propertyDef['$ref']); 374 throw new Error('No custom binding for ' + propertyDef['$ref']);
384 var args = value; 375 var args = value;
385 // For an object propertyDef, |value| is an array of constructor 376 // For an object propertyDef, |value| is an array of constructor
386 // arguments, but we want to pass the arguments directly (i.e. 377 // arguments, but we want to pass the arguments directly (i.e.
387 // not as an array), so we have to fake calling |new| on the 378 // not as an array), so we have to fake calling |new| on the
388 // constructor. 379 // constructor.
389 value = { __proto__: constructor.prototype }; 380 value = { __proto__: constructor.prototype };
390 constructor.apply(value, args); 381 constructor.apply(value, args);
391 // Recursively add properties. 382 // Recursively add properties.
(...skipping 10 matching lines...) Expand all
402 }); 393 });
403 }; 394 };
404 395
405 addProperties(mod, schema); 396 addProperties(mod, schema);
406 this.runHooks_(mod); 397 this.runHooks_(mod);
407 return mod; 398 return mod;
408 } 399 }
409 }; 400 };
410 401
411 exports.Binding = Binding; 402 exports.Binding = Binding;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698