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) { | |
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); | |
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 scehma. | |
Matt Perry
2012/02/16 00:31:08
schema*
Matt Tytel
2012/02/24 01:29:27
Done.
| |
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 var signature = remaining[i].slice(0); | |
79 signature.unshift(schemas[0]); | |
80 signatures.push(signature); | |
Matt Perry
2012/02/16 00:31:08
could do this more simply as signatures.push([sche
Matt Tytel
2012/02/24 01:29:27
Done.
| |
81 } | |
82 if (schemas[0].optional) | |
83 return signatures.concat(remaining); | |
84 return signatures; | |
85 }; | |
86 | |
87 // Return true if arguments match a given signature's schema. | |
88 chromeHidden.argumentsMatchSignature = function(args, schemas) { | |
89 if (args.length != schemas.length) | |
90 return false; | |
91 | |
92 for (var i = 0; i < schemas.length; i++) { | |
93 if (!chromeHidden.isValidSchemaType( | |
94 chromeHidden.JSONSchemaValidator.getType(args[i]), schemas[i])) | |
95 return false; | |
96 } | |
97 return true; | |
98 }; | |
99 | |
100 // Finds the function signature for the given arguments. | |
101 chromeHidden.matchSignature = function(args, schemas) { | |
Matt Perry
2012/02/16 00:31:08
The implementation here is somewhat wasteful. You
Matt Tytel
2012/02/16 04:35:02
I think this a code efficiency vs code simplicity
Matt Perry
2012/02/16 19:21:29
Yep. I think you made the right tradeoff here.
| |
102 var signatures = chromeHidden.getSignatures(schemas); | |
103 for (var i = 0; i < signatures.length; i++) { | |
104 if (chromeHidden.argumentsMatchSignature(args, signatures[i])) | |
105 return signatures[i]; | |
106 } | |
107 return null; | |
108 }; | |
109 | |
110 // Validates that a given schema for an API function is not ambiguous. | |
111 chromeHidden.isSchemaAmbiguous = function(schema) { | |
112 var signaturesAmbiguous = function(signature1, signature2) { | |
113 if (signature1.length != signature2.length) | |
114 return false; | |
115 | |
116 for (var i = 0; i < signature1.length; i++) { | |
117 if (!chromeHidden.checkSchemaOverlap(signature1[i], signature2[i])) | |
118 return false; | |
119 } | |
120 return true; | |
121 }; | |
122 | |
123 var signatures = chromeHidden.getSignatures(schema); | |
124 for (var i = 0; i < signatures.length; i++) { | |
125 for (var j = i + 1; j < signatures.length; j++) { | |
126 if (signaturesAmbiguous(signatures[i], signatures[j])) | |
127 return true; | |
128 } | |
129 } | |
130 return false; | |
131 }; | |
132 | |
34 // Validate arguments. | 133 // Validate arguments. |
35 chromeHidden.validationTypes = []; | 134 chromeHidden.validationTypes = []; |
36 chromeHidden.validate = function(args, schemas) { | 135 chromeHidden.validate = function(args, schemas) { |
37 if (args.length > schemas.length) | 136 if (args.length > schemas.length) |
38 throw new Error("Too many arguments."); | 137 throw new Error("Too many arguments."); |
39 | 138 |
40 for (var i = 0; i < schemas.length; i++) { | 139 for (var i = 0; i < schemas.length; i++) { |
41 if (i in args && args[i] !== null && args[i] !== undefined) { | 140 if (i in args && args[i] !== null && args[i] !== undefined) { |
42 var validator = new chromeHidden.JSONSchemaValidator(); | 141 var validator = new chromeHidden.JSONSchemaValidator(); |
43 validator.addTypes(chromeHidden.validationTypes); | 142 validator.addTypes(chromeHidden.validationTypes); |
(...skipping 13 matching lines...) Expand all Loading... | |
57 message = message.substring(0, message.length - 2); | 156 message = message.substring(0, message.length - 2); |
58 message += "."; | 157 message += "."; |
59 | 158 |
60 throw new Error(message); | 159 throw new Error(message); |
61 } else if (!schemas[i].optional) { | 160 } else if (!schemas[i].optional) { |
62 throw new Error("Parameter " + (i + 1) + " is required."); | 161 throw new Error("Parameter " + (i + 1) + " is required."); |
63 } | 162 } |
64 } | 163 } |
65 }; | 164 }; |
66 | 165 |
166 // Returns a string representing the defined signature of the API function. | |
167 // Example return value for chrome.windows.getCurrent: | |
168 // "windows.getCurrent(optional object populate, function callback)" | |
169 chromeHidden.getSchemaSignatureString = function(name, schemas) { | |
170 var getSchemaTypeString = function(schema) { | |
171 var schema_types = chromeHidden.getAllTypesForSchema(schema); | |
172 var type_name = schema_types.join(" or ") + " " + schema.name; | |
173 if (schema.optional) | |
174 return "optional " + type_name; | |
175 return type_name; | |
176 }; | |
177 | |
178 var type_names = schemas.map(getSchemaTypeString); | |
179 return name +"(" + type_names.join(", ") + ")"; | |
Matt Perry
2012/02/16 00:31:08
space before "("
Matt Tytel
2012/02/24 01:29:27
Done.
| |
180 }; | |
181 | |
182 // Returns a string representing a call to an API function | |
183 // Example return value for call: chrome.windows.get(1, callback) is: | |
184 // "windows.get(int, function)" | |
185 chromeHidden.getArgumentSignatureString = function(name, args) { | |
186 var type_names = args.map(chromeHidden.JSONSchemaValidator.getType); | |
187 return name +"(" + type_names.join(", ") + ")"; | |
Matt Perry
2012/02/16 00:31:08
space before "("
Matt Tytel
2012/02/24 01:29:27
Done.
| |
188 }; | |
189 | |
190 // Finds the correct signature for the given arguments | |
Matt Perry
2012/02/16 00:31:08
end sentence with .
Matt Tytel
2012/02/24 01:29:27
Done.
| |
191 chromeHidden.matchSignatureAndValidate = function(args, fun_def) { | |
192 var schemas = fun_def.definition.parameters; | |
193 var match = chromeHidden.matchSignature(args, schemas); | |
194 if (!match) | |
195 throw new Error("Invocation of form " + | |
196 chromeHidden.getArgumentSignatureString(fun_def.name, args) + | |
197 " doesn't match definition " + | |
198 chromeHidden.getSchemaSignatureString(fun_def.name, schemas)); | |
199 chromeHidden.validate(args, match); | |
200 | |
201 var normalized_args = []; | |
202 var ai = 0; | |
203 for (var si = 0; si < schemas.length; si++) { | |
204 if (schemas[si] === match[ai]) | |
205 normalized_args.push(args[ai++]); | |
206 else | |
207 normalized_args.push(null); | |
208 } | |
209 return normalized_args; | |
210 }; | |
211 | |
67 // Callback handling. | 212 // Callback handling. |
68 var requests = []; | 213 var requests = []; |
69 chromeHidden.handleResponse = function(requestId, name, | 214 chromeHidden.handleResponse = function(requestId, name, |
70 success, response, error) { | 215 success, response, error) { |
71 try { | 216 try { |
72 var request = requests[requestId]; | 217 var request = requests[requestId]; |
73 if (success) { | 218 if (success) { |
74 delete chrome.extension.lastError; | 219 delete chrome.extension.lastError; |
75 } else { | 220 } else { |
76 if (!error) { | 221 if (!error) { |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
429 | 574 |
430 if (functionDef.name in module || | 575 if (functionDef.name in module || |
431 addUnprivilegedAccessGetter(module, functionDef.name, | 576 addUnprivilegedAccessGetter(module, functionDef.name, |
432 functionDef.unprivileged)) { | 577 functionDef.unprivileged)) { |
433 return; | 578 return; |
434 } | 579 } |
435 | 580 |
436 var apiFunction = {}; | 581 var apiFunction = {}; |
437 apiFunction.definition = functionDef; | 582 apiFunction.definition = functionDef; |
438 apiFunction.name = apiDef.namespace + "." + functionDef.name; | 583 apiFunction.name = apiDef.namespace + "." + functionDef.name; |
584 | |
585 // Validate API for ambiguity only in DEBUG mode. | |
586 if (chromeHidden.validateAPI && | |
587 chromeHidden.isSchemaAmbiguous(apiFunction.definition.parameters)) | |
588 throw new Error(apiFunction.name + " is ambiguous"); | |
439 apiFunctions.register(apiFunction.name, apiFunction); | 589 apiFunctions.register(apiFunction.name, apiFunction); |
440 | 590 |
441 module[functionDef.name] = (function() { | 591 module[functionDef.name] = (function() { |
442 var args = arguments; | 592 var args = Array.prototype.slice.call(arguments); |
443 if (this.updateArgumentsPreValidate) | 593 if (this.updateArgumentsPreValidate) |
444 args = this.updateArgumentsPreValidate.apply(this, args); | 594 args = this.updateArgumentsPreValidate.apply(this, args); |
445 chromeHidden.validate(args, this.definition.parameters); | 595 |
596 args = chromeHidden.matchSignatureAndValidate(args, this); | |
446 if (this.updateArgumentsPostValidate) | 597 if (this.updateArgumentsPostValidate) |
447 args = this.updateArgumentsPostValidate.apply(this, args); | 598 args = this.updateArgumentsPostValidate.apply(this, args); |
448 | 599 |
449 var retval; | 600 var retval; |
450 if (this.handleRequest) { | 601 if (this.handleRequest) { |
451 retval = this.handleRequest.apply(this, args); | 602 retval = this.handleRequest.apply(this, args); |
452 } else { | 603 } else { |
453 retval = sendRequest(this.name, args, | 604 retval = sendRequest(this.name, args, |
454 this.definition.parameters, | 605 this.definition.parameters, |
455 {customCallback: this.customCallback}); | 606 {customCallback: this.customCallback}); |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
575 // See http://crbug.com/100242 | 726 // See http://crbug.com/100242 |
576 if (chrome.webstorePrivate) { | 727 if (chrome.webstorePrivate) { |
577 chrome.webstorePrivate.beginInstallWithManifest2 = | 728 chrome.webstorePrivate.beginInstallWithManifest2 = |
578 chrome.webstorePrivate.beginInstallWithManifest3; | 729 chrome.webstorePrivate.beginInstallWithManifest3; |
579 } | 730 } |
580 | 731 |
581 if (chrome.test) | 732 if (chrome.test) |
582 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; | 733 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; |
583 }); | 734 }); |
584 })(); | 735 })(); |
OLD | NEW |