1 // Copyright 2014 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.
5 var GetAvailability = requireNative('v8_context').GetAvailability;
6 var GetGlobal = requireNative('sendRequest').GetGlobal;
8 // Utility for setting chrome.*.lastError.
10 // A utility here is useful for two reasons:
11 // 1. For backwards compatibility we need to set chrome.extension.lastError,
12 // but not all contexts actually have access to the extension namespace.
13 // 2. When calling across contexts, the global object that gets lastError set
14 // needs to be that of the caller. We force callers to explicitly specify
15 // the chrome object to try to prevent bugs here.
18 * Sets the last error for |name| on |targetChrome| to |message| with an
21 function set(name, message, stack, targetChrome) {
23 var errorMessage = name + ': ' + message;
24 if (stack != null && stack != '')
25 errorMessage += '\n' + stack;
26 throw new Error('No chrome object to set error: ' + errorMessage);
28 clear(targetChrome); // in case somebody has set a sneaky getter/setter
30 var errorObject = { message: message };
31 if (GetAvailability('extension.lastError').is_available)
32 targetChrome.extension.lastError = errorObject;
34 assertRuntimeIsAvailable();
36 // We check to see if developers access runtime.lastError in order to decide
37 // whether or not to log it in the (error) console.
38 privates(targetChrome.runtime).accessedLastError = false;
39 $Object.defineProperty(targetChrome.runtime, 'lastError', {
42 privates(targetChrome.runtime).accessedLastError = true;
45 set: function(error) {
46 errorObject = errorObject;
51 * Check if anyone has checked chrome.runtime.lastError since it was set.
52 * @param {Object} targetChrome the Chrome object to check.
53 * @return boolean True if the lastError property was set.
55 function hasAccessed(targetChrome) {
56 assertRuntimeIsAvailable();
57 return privates(targetChrome.runtime).accessedLastError === true;
61 * Check whether there is an error set on |targetChrome| without setting
62 * |accessedLastError|.
63 * @param {Object} targetChrome the Chrome object to check.
64 * @return boolean Whether lastError has been set.
66 function hasError(targetChrome) {
68 throw new Error('No target chrome to check');
70 assertRuntimeIsAvailable();
71 if ('lastError' in targetChrome.runtime)
78 * Clears the last error on |targetChrome|.
80 function clear(targetChrome) {
82 throw new Error('No target chrome to clear error');
84 if (GetAvailability('extension.lastError').is_available)
85 delete targetChrome.extension.lastError;
87 assertRuntimeIsAvailable();
88 delete targetChrome.runtime.lastError;
89 delete privates(targetChrome.runtime).accessedLastError;
92 function assertRuntimeIsAvailable() {
93 // chrome.runtime should always be available, but maybe it's disappeared for
94 // some reason? Add debugging for http://crbug.com/258526.
95 var runtimeAvailability = GetAvailability('runtime.lastError');
96 if (!runtimeAvailability.is_available) {
97 throw new Error('runtime.lastError is not available: ' +
98 runtimeAvailability.message);
101 throw new Error('runtime namespace is null or undefined');
105 * Runs |callback(args)| with last error args as in set().
107 * The target chrome object is the global object's of the callback, so this
108 * method won't work if the real callback has been wrapped (etc).
110 function run(name, message, stack, callback, args) {
111 var targetChrome = GetGlobal(callback).chrome;
112 set(name, message, stack, targetChrome);
114 $Function.apply(callback, undefined, args);
116 reportIfUnchecked(name, targetChrome, stack);
122 * Checks whether chrome.runtime.lastError has been accessed if set.
123 * If it was set but not accessed, the error is reported to the console.
125 * @param {string=} name - name of API.
126 * @param {Object} targetChrome - the Chrome object to check.
127 * @param {string=} stack - Stack trace of the call up to the error.
129 function reportIfUnchecked(name, targetChrome, stack) {
130 if (hasAccessed(targetChrome) || !hasError(targetChrome))
132 var message = targetChrome.runtime.lastError.message;
133 console.error("Unchecked runtime.lastError while running " +
134 (name || "unknown") + ": " + message + (stack ? "\n" + stack : ""));
137 exports.clear = clear;
138 exports.hasAccessed = hasAccessed;
139 exports.hasError = hasError;
142 exports.reportIfUnchecked = reportIfUnchecked;