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 13 matching lines...) Expand all Loading... | |
24 var internalAPIs = {}; | 24 var internalAPIs = {}; |
25 chromeHidden.internalAPIs = internalAPIs; | 25 chromeHidden.internalAPIs = internalAPIs; |
26 | 26 |
27 function forEach(dict, f) { | 27 function forEach(dict, f) { |
28 for (key in dict) { | 28 for (key in dict) { |
29 if (dict.hasOwnProperty(key)) | 29 if (dict.hasOwnProperty(key)) |
30 f(key, dict[key]); | 30 f(key, dict[key]); |
31 } | 31 } |
32 } | 32 } |
33 | 33 |
34 // Returns a list of types that this schema allows. | |
35 chromeHidden.getAllTypesForSchema = function(schema) { | |
Aaron Boodman
2012/02/16 21:36:54
Button a function on chromeHidden basically export
Matt Tytel
2012/02/24 01:29:27
Done.
| |
36 var validator = new chromeHidden.JSONSchemaValidator(); | |
37 validator.addTypes(chromeHidden.validationTypes); | |
38 var schema_types = []; | |
39 if (schema.type) | |
40 schema_types.push(schema.type); | |
41 if (schema.choices) { | |
42 for (var i = 0; i < schema.choices.length; i++) | |
43 schema_types.push(schema.choices[i].type); | |
44 } | |
45 if (schema['$ref']) | |
46 schema_types.push(validator.types[schema['$ref']].type); | |
Aaron Boodman
2012/02/16 21:36:54
What if it has choices?
Matt Tytel
2012/02/24 01:29:27
Done. I don't think any have any choices or link t
| |
47 return schema_types; | |
48 }; | |
49 | |
50 // Returns true if |schema| would accept an argument of type |type|. | |
51 chromeHidden.isValidSchemaType = function(type, schema) { | |
52 schema_types = chromeHidden.getAllTypesForSchema(schema); | |
53 for (var i = 0; i < schema_types.length; i++) { | |
54 if (schema_types[i] == "any" || type == schema_types[i]) | |
55 return true; | |
56 } | |
57 return type == "any"; | |
58 }; | |
59 | |
60 // Returns true if there is a non-null value that both schemas would accept. | |
61 chromeHidden.checkSchemaOverlap = function(schema1, schema2) { | |
62 schema_types1 = chromeHidden.getAllTypesForSchema(schema1); | |
63 for (var i = 0; i < schema_types1.length; i++) { | |
64 if (chromeHidden.isValidSchemaType(schema_types1[i], schema2)) | |
65 return true; | |
66 } | |
67 return false; | |
68 }; | |
69 | |
70 // Generate all possible signatures for a given API function schema. | |
71 chromeHidden.getSignatures = function(schemas) { | |
72 if (schemas.length === 0) | |
73 return [[]]; | |
74 | |
75 var signatures = []; | |
76 var remaining = chromeHidden.getSignatures(schemas.slice(1)); | |
77 for (var i = 0; i < remaining.length; i++) | |
78 signatures.push([schemas[0]].concat(remaining[i])) | |
79 | |
80 if (schemas[0].optional) | |
81 return signatures.concat(remaining); | |
82 return signatures; | |
83 }; | |
84 | |
85 // Return true if arguments match a given signature's schema. | |
86 chromeHidden.argumentsMatchSignature = function(args, schemas) { | |
87 if (args.length != schemas.length) | |
88 return false; | |
89 | |
90 for (var i = 0; i < schemas.length; i++) { | |
91 if (!chromeHidden.isValidSchemaType( | |
92 chromeHidden.JSONSchemaValidator.getType(args[i]), schemas[i])) | |
93 return false; | |
94 } | |
95 return true; | |
96 }; | |
97 | |
98 // Finds the function signature for the given arguments. | |
99 chromeHidden.matchSignature = function(args, schemas) { | |
100 var signatures = chromeHidden.getSignatures(schemas); | |
101 for (var i = 0; i < signatures.length; i++) { | |
102 if (chromeHidden.argumentsMatchSignature(args, signatures[i])) | |
103 return signatures[i]; | |
104 } | |
105 return null; | |
106 }; | |
107 | |
108 // Validates that a given schema for an API function is not ambiguous. | |
109 chromeHidden.isSchemaAmbiguous = function(schema) { | |
Aaron Boodman
2012/02/16 21:36:54
The terms in use here are getting a bit overloaded
Matt Tytel
2012/02/24 01:29:27
Done.
| |
110 var signaturesAmbiguous = function(signature1, signature2) { | |
111 if (signature1.length != signature2.length) | |
112 return false; | |
113 | |
114 for (var i = 0; i < signature1.length; i++) { | |
115 if (!chromeHidden.checkSchemaOverlap(signature1[i], signature2[i])) | |
116 return false; | |
117 } | |
118 return true; | |
119 }; | |
120 | |
121 var signatures = chromeHidden.getSignatures(schema); | |
122 for (var i = 0; i < signatures.length; i++) { | |
123 for (var j = i + 1; j < signatures.length; j++) { | |
124 if (signaturesAmbiguous(signatures[i], signatures[j])) | |
125 return true; | |
126 } | |
127 } | |
128 return false; | |
129 }; | |
130 | |
34 // Validate arguments. | 131 // Validate arguments. |
35 chromeHidden.validationTypes = []; | 132 chromeHidden.validationTypes = []; |
36 chromeHidden.validate = function(args, schemas) { | 133 chromeHidden.validate = function(args, schemas) { |
37 if (args.length > schemas.length) | 134 if (args.length > schemas.length) |
38 throw new Error("Too many arguments."); | 135 throw new Error("Too many arguments."); |
39 | 136 |
40 for (var i = 0; i < schemas.length; i++) { | 137 for (var i = 0; i < schemas.length; i++) { |
41 if (i in args && args[i] !== null && args[i] !== undefined) { | 138 if (i in args && args[i] !== null && args[i] !== undefined) { |
42 var validator = new chromeHidden.JSONSchemaValidator(); | 139 var validator = new chromeHidden.JSONSchemaValidator(); |
43 validator.addTypes(chromeHidden.validationTypes); | 140 validator.addTypes(chromeHidden.validationTypes); |
(...skipping 13 matching lines...) Expand all Loading... | |
57 message = message.substring(0, message.length - 2); | 154 message = message.substring(0, message.length - 2); |
58 message += "."; | 155 message += "."; |
59 | 156 |
60 throw new Error(message); | 157 throw new Error(message); |
61 } else if (!schemas[i].optional) { | 158 } else if (!schemas[i].optional) { |
62 throw new Error("Parameter " + (i + 1) + " is required."); | 159 throw new Error("Parameter " + (i + 1) + " is required."); |
63 } | 160 } |
64 } | 161 } |
65 }; | 162 }; |
66 | 163 |
164 // Returns a string representing the defined signature of the API function. | |
165 // Example return value for chrome.windows.getCurrent: | |
166 // "windows.getCurrent(optional object populate, function callback)" | |
167 chromeHidden.getSchemaSignatureString = function(name, schemas) { | |
168 var getSchemaTypeString = function(schema) { | |
169 var schema_types = chromeHidden.getAllTypesForSchema(schema); | |
170 var type_name = schema_types.join(" or ") + " " + schema.name; | |
171 if (schema.optional) | |
172 return "optional " + type_name; | |
173 return type_name; | |
174 }; | |
175 | |
176 var type_names = schemas.map(getSchemaTypeString); | |
177 return name +" (" + type_names.join(", ") + ")"; | |
178 }; | |
179 | |
180 // Returns a string representing a call to an API function. | |
181 // Example return value for call: chrome.windows.get(1, callback) is: | |
182 // "windows.get(int, function)" | |
183 chromeHidden.getArgumentSignatureString = function(name, args) { | |
184 var type_names = args.map(chromeHidden.JSONSchemaValidator.getType); | |
185 return name +" (" + type_names.join(", ") + ")"; | |
186 }; | |
187 | |
188 // Finds the correct signature for the given arguments. | |
not at google - send to devlin
2012/02/17 00:47:11
I think this comment (and function name) is not qu
Matt Tytel
2012/02/24 01:29:27
Done.
| |
189 chromeHidden.matchSignatureAndValidate = function(args, fun_def) { | |
190 var schemas = fun_def.definition.parameters; | |
191 var match = chromeHidden.matchSignature(args, schemas); | |
192 if (!match) | |
193 throw new Error("Invocation of form " + | |
194 chromeHidden.getArgumentSignatureString(fun_def.name, args) + | |
195 " doesn't match definition " + | |
196 chromeHidden.getSchemaSignatureString(fun_def.name, schemas)); | |
197 chromeHidden.validate(args, match); | |
198 | |
199 var normalized_args = []; | |
200 var ai = 0; | |
201 for (var si = 0; si < schemas.length; si++) { | |
202 if (schemas[si] === match[ai]) | |
203 normalized_args.push(args[ai++]); | |
204 else | |
205 normalized_args.push(null); | |
206 } | |
207 return normalized_args; | |
208 }; | |
209 | |
67 // Callback handling. | 210 // Callback handling. |
68 var requests = []; | 211 var requests = []; |
69 chromeHidden.handleResponse = function(requestId, name, | 212 chromeHidden.handleResponse = function(requestId, name, |
70 success, response, error) { | 213 success, response, error) { |
71 try { | 214 try { |
72 var request = requests[requestId]; | 215 var request = requests[requestId]; |
73 if (success) { | 216 if (success) { |
74 delete chrome.extension.lastError; | 217 delete chrome.extension.lastError; |
75 } else { | 218 } else { |
76 if (!error) { | 219 if (!error) { |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
429 | 572 |
430 if (functionDef.name in module || | 573 if (functionDef.name in module || |
431 addUnprivilegedAccessGetter(module, functionDef.name, | 574 addUnprivilegedAccessGetter(module, functionDef.name, |
432 functionDef.unprivileged)) { | 575 functionDef.unprivileged)) { |
433 return; | 576 return; |
434 } | 577 } |
435 | 578 |
436 var apiFunction = {}; | 579 var apiFunction = {}; |
437 apiFunction.definition = functionDef; | 580 apiFunction.definition = functionDef; |
438 apiFunction.name = apiDef.namespace + "." + functionDef.name; | 581 apiFunction.name = apiDef.namespace + "." + functionDef.name; |
582 | |
583 // Validate API for ambiguity only in DEBUG mode. | |
Aaron Boodman
2012/02/16 21:36:54
Can you add this here please:
TODO(aa): It would
Matt Tytel
2012/02/24 01:29:27
Done.
| |
584 if (chromeHidden.validateAPI && | |
585 chromeHidden.isSchemaAmbiguous(apiFunction.definition.parameters)) | |
586 throw new Error(apiFunction.name + " is ambiguous"); | |
439 apiFunctions.register(apiFunction.name, apiFunction); | 587 apiFunctions.register(apiFunction.name, apiFunction); |
440 | 588 |
441 module[functionDef.name] = (function() { | 589 module[functionDef.name] = (function() { |
442 var args = arguments; | 590 var args = Array.prototype.slice.call(arguments); |
443 if (this.updateArgumentsPreValidate) | 591 if (this.updateArgumentsPreValidate) |
444 args = this.updateArgumentsPreValidate.apply(this, args); | 592 args = this.updateArgumentsPreValidate.apply(this, args); |
445 chromeHidden.validate(args, this.definition.parameters); | 593 |
594 args = chromeHidden.matchSignatureAndValidate(args, this); | |
446 if (this.updateArgumentsPostValidate) | 595 if (this.updateArgumentsPostValidate) |
447 args = this.updateArgumentsPostValidate.apply(this, args); | 596 args = this.updateArgumentsPostValidate.apply(this, args); |
448 | 597 |
449 var retval; | 598 var retval; |
450 if (this.handleRequest) { | 599 if (this.handleRequest) { |
451 retval = this.handleRequest.apply(this, args); | 600 retval = this.handleRequest.apply(this, args); |
452 } else { | 601 } else { |
453 retval = sendRequest(this.name, args, | 602 retval = sendRequest(this.name, args, |
454 this.definition.parameters, | 603 this.definition.parameters, |
455 {customCallback: this.customCallback}); | 604 {customCallback: this.customCallback}); |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
575 // See http://crbug.com/100242 | 724 // See http://crbug.com/100242 |
576 if (chrome.webstorePrivate) { | 725 if (chrome.webstorePrivate) { |
577 chrome.webstorePrivate.beginInstallWithManifest2 = | 726 chrome.webstorePrivate.beginInstallWithManifest2 = |
578 chrome.webstorePrivate.beginInstallWithManifest3; | 727 chrome.webstorePrivate.beginInstallWithManifest3; |
579 } | 728 } |
580 | 729 |
581 if (chrome.test) | 730 if (chrome.test) |
582 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; | 731 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; |
583 }); | 732 }); |
584 })(); | 733 })(); |
OLD | NEW |