1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 // We are going to kill all of the builtins, so hold onto the ones we need.
8 var defineGetter = Object.prototype.__defineGetter__;
9 var defineSetter = Object.prototype.__defineSetter__;
10 var Error = window.Error;
11 var forEach = Array.prototype.forEach;
12 var push = Array.prototype.push;
13 var hasOwnProperty = Object.prototype.hasOwnProperty;
14 var getOwnPropertyNames = Object.getOwnPropertyNames;
15 var stringify = JSON.stringify;
17 // Kill all of the builtins functions to give us a fairly high confidence that
18 // the environment our bindings run in can't interfere with our code.
19 // These are taken from the ECMAScript spec.
21 Object, Function, Array, String, Boolean, Number, Math, Date, RegExp, JSON,
24 function clobber(obj, name, qualifiedName) {
25 // Clobbering constructors would break everything.
26 // Clobbering toString is annoying.
27 // Clobbering __proto__ breaks in ways that grep can't find.
28 // Clobbering Function.call would make it impossible to implement these tests.
29 // Clobbering Object.valueOf breaks v8.
30 if (name == 'constructor' ||
32 name == '__proto__' ||
33 qualifiedName == 'Function.call' ||
34 qualifiedName == 'Object.valueOf') {
37 if (typeof(obj[name]) == 'function') {
38 obj[name] = function() {
39 throw new Error('Clobbered ' + qualifiedName + ' function');
42 defineGetter.call(obj, name, function() {
43 throw new Error('Clobbered ' + qualifiedName + ' getter');
48 forEach.call(builtinTypes, function(builtin) {
49 var prototype = builtin.prototype;
50 var typename = '<unknown>';
52 typename = prototype.constructor.name;
53 forEach.call(getOwnPropertyNames(prototype), function(name) {
54 clobber(prototype, name, typename + '.' + name);
57 forEach.call(getOwnPropertyNames(builtin), function(name) {
58 clobber(builtin, name, typename + '.' + name);
61 clobber(window, builtin.name, 'window.' + builtin.name);
64 // Codes for test results. Must match ExternallyConnectableMessagingTest::Result
65 // in c/b/extensions/extension_messages_apitest.cc.
68 NAMESPACE_NOT_DEFINED: 1,
69 FUNCTION_NOT_DEFINED: 2,
70 COULD_NOT_ESTABLISH_CONNECTION_ERROR: 3,
72 INCORRECT_RESPONSE_SENDER: 5,
73 INCORRECT_RESPONSE_MESSAGE: 6,
76 // Make the messages sent vaguely complex, but unambiguously JSON-ifiable.
77 var kMessage = [{'a': {'b': 10}}, 20, 'c\x10\x11'];
79 // Our tab's location. Normally this would be our document's location but if
80 // we're an iframe it will be the location of the parent - in which case,
82 var tabLocationHref = null;
84 if (parent == window) {
85 tabLocationHref = document.location.href;
87 window.addEventListener('message', function listener(event) {
88 window.removeEventListener(listener);
89 tabLocationHref = event.data;
93 function checkLastError(reply) {
94 if (!chrome.runtime.lastError)
96 var kCouldNotEstablishConnection =
97 'Could not establish connection. Receiving end does not exist.';
98 if (chrome.runtime.lastError.message == kCouldNotEstablishConnection)
99 reply(results.COULD_NOT_ESTABLISH_CONNECTION_ERROR);
101 reply(results.OTHER_ERROR);
105 function checkResponse(response, reply, expectedMessage) {
106 // The response will be an echo of both the original message *and* the
107 // MessageSender (with the tab field stripped down).
109 // First check the sender was correct.
110 var incorrectSender = false;
111 if (!hasOwnProperty.call(response.sender, 'tab')) {
112 console.warn('Expected a tab, got none');
113 incorrectSender = true;
115 if (response.sender.tab.url != tabLocationHref) {
116 console.warn('Expected tab url ' + tabLocationHref + ' got ' +
117 response.sender.tab.url);
118 incorrectSender = true;
120 if (hasOwnProperty.call(response.sender, 'id')) {
121 console.warn('Expected no id, got "' + response.sender.id + '"');
122 incorrectSender = true;
124 if (response.sender.url != document.location.href) {
125 console.warn('Expected url ' + document.location.href + ' got ' +
126 response.sender.url);
127 incorrectSender = true;
129 if (incorrectSender) {
130 reply(results.INCORRECT_RESPONSE_SENDER);
134 // Check the correct content was echoed.
135 var expectedJson = stringify(expectedMessage);
136 var actualJson = stringify(response.message);
137 if (actualJson == expectedJson)
139 console.warn('Expected message ' + expectedJson + ' got ' + actualJson);
140 reply(results.INCORRECT_RESPONSE_MESSAGE);
144 function sendToBrowser(msg) {
145 domAutomationController.send(msg);
148 function sendToBrowserForTlsChannelId(result) {
149 // Because the TLS channel ID tests read the TLS either an error code or the
150 // TLS channel ID string from the same value, they require the result code
151 // to be sent as a string.
152 // String() is clobbered, so coerce string creation with +.
153 sendToBrowser("" + result);
156 function checkRuntime(reply) {
158 reply = sendToBrowser;
160 if (!chrome.runtime) {
161 reply(results.NAMESPACE_NOT_DEFINED);
165 if (!chrome.runtime.connect || !chrome.runtime.sendMessage) {
166 reply(results.FUNCTION_NOT_DEFINED);
172 function checkRuntimeForTlsChannelId() {
173 return checkRuntime(sendToBrowserForTlsChannelId);
176 function checkTlsChannelIdResponse(response) {
177 if (chrome.runtime.lastError) {
178 if (chrome.runtime.lastError.message == kCouldNotEstablishConnection)
179 sendToBrowserForTlsChannelId(
180 results.COULD_NOT_ESTABLISH_CONNECTION_ERROR);
182 sendToBrowserForTlsChannelId(results.OTHER_ERROR);
185 if (response.sender.tlsChannelId !== undefined)
186 sendToBrowserForTlsChannelId(response.sender.tlsChannelId);
188 sendToBrowserForTlsChannelId('');
192 appendIframe: function(src) {
193 var iframe = document.createElement('iframe');
194 // When iframe has loaded, notify it of our tab location (probably
195 // document.location) to use in its assertions, then continue.
196 iframe.addEventListener('load', function listener() {
197 iframe.removeEventListener('load', listener);
198 iframe.contentWindow.postMessage(tabLocationHref, '*');
202 document.body.appendChild(iframe);
206 window.assertions = {
207 canConnectAndSendMessages: function(extensionId, message) {
217 function canSendMessage(reply) {
218 chrome.runtime.sendMessage(extensionId, message, function(response) {
219 if (checkLastError(reply) && checkResponse(response, reply, message))
224 function canConnectAndSendMessages(reply) {
225 var port = chrome.runtime.connect(extensionId);
226 port.postMessage(message, function() {
227 checkLastError(reply);
229 port.postMessage(message, function() {
230 checkLastError(reply);
232 var pendingResponses = 2;
234 port.onMessage.addListener(function(response) {
236 ok = ok && checkLastError(reply) &&
237 checkResponse(response, reply, message);
238 if (pendingResponses == 0 && ok)
243 canSendMessage(function(result) {
244 if (result != results.OK)
245 sendToBrowser(result);
247 canConnectAndSendMessages(sendToBrowser);
251 areAnyRuntimePropertiesDefined: function(names) {
253 if (chrome.runtime) {
254 forEach.call(names, function(name) {
255 if (chrome.runtime[name]) {
256 console.log('runtime.' + name + ' is defined');
261 sendToBrowser(result);
264 getTlsChannelIdFromPortConnect: function(extensionId, includeTlsChannelId,
266 if (!checkRuntimeForTlsChannelId())
272 var port = chrome.runtime.connect(extensionId,
273 {'includeTlsChannelId': includeTlsChannelId});
274 port.onMessage.addListener(checkTlsChannelIdResponse);
275 port.postMessage(message);
278 getTlsChannelIdFromSendMessage: function(extensionId, includeTlsChannelId,
280 if (!checkRuntimeForTlsChannelId())
286 chrome.runtime.sendMessage(extensionId, message,
287 {'includeTlsChannelId': includeTlsChannelId},
288 checkTlsChannelIdResponse);