summaryrefslogtreecommitdiff
path: root/chromium/extensions/renderer/resources/last_error.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/extensions/renderer/resources/last_error.js')
-rw-r--r--chromium/extensions/renderer/resources/last_error.js143
1 files changed, 143 insertions, 0 deletions
diff --git a/chromium/extensions/renderer/resources/last_error.js b/chromium/extensions/renderer/resources/last_error.js
new file mode 100644
index 00000000000..fc0c7b5e4d3
--- /dev/null
+++ b/chromium/extensions/renderer/resources/last_error.js
@@ -0,0 +1,143 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var GetAvailability = requireNative('v8_context').GetAvailability;
+var GetGlobal = requireNative('sendRequest').GetGlobal;
+
+// Utility for setting chrome.*.lastError.
+//
+// A utility here is useful for two reasons:
+// 1. For backwards compatibility we need to set chrome.extension.lastError,
+// but not all contexts actually have access to the extension namespace.
+// 2. When calling across contexts, the global object that gets lastError set
+// needs to be that of the caller. We force callers to explicitly specify
+// the chrome object to try to prevent bugs here.
+
+/**
+ * Sets the last error for |name| on |targetChrome| to |message| with an
+ * optional |stack|.
+ */
+function set(name, message, stack, targetChrome) {
+ if (!targetChrome) {
+ var errorMessage = name + ': ' + message;
+ if (stack != null && stack != '')
+ errorMessage += '\n' + stack;
+ throw new Error('No chrome object to set error: ' + errorMessage);
+ }
+ clear(targetChrome); // in case somebody has set a sneaky getter/setter
+
+ var errorObject = { message: message };
+ if (GetAvailability('extension.lastError').is_available)
+ targetChrome.extension.lastError = errorObject;
+
+ assertRuntimeIsAvailable();
+
+ // We check to see if developers access runtime.lastError in order to decide
+ // whether or not to log it in the (error) console.
+ privates(targetChrome.runtime).accessedLastError = false;
+ $Object.defineProperty(targetChrome.runtime, 'lastError', {
+ configurable: true,
+ get: function() {
+ privates(targetChrome.runtime).accessedLastError = true;
+ return errorObject;
+ },
+ set: function(error) {
+ errorObject = errorObject;
+ }});
+};
+
+/**
+ * Check if anyone has checked chrome.runtime.lastError since it was set.
+ * @param {Object} targetChrome the Chrome object to check.
+ * @return boolean True if the lastError property was set.
+ */
+function hasAccessed(targetChrome) {
+ assertRuntimeIsAvailable();
+ return privates(targetChrome.runtime).accessedLastError === true;
+}
+
+/**
+ * Check whether there is an error set on |targetChrome| without setting
+ * |accessedLastError|.
+ * @param {Object} targetChrome the Chrome object to check.
+ * @return boolean Whether lastError has been set.
+ */
+function hasError(targetChrome) {
+ if (!targetChrome)
+ throw new Error('No target chrome to check');
+
+ assertRuntimeIsAvailable();
+ if ('lastError' in targetChrome.runtime)
+ return true;
+
+ return false;
+};
+
+/**
+ * Clears the last error on |targetChrome|.
+ */
+function clear(targetChrome) {
+ if (!targetChrome)
+ throw new Error('No target chrome to clear error');
+
+ if (GetAvailability('extension.lastError').is_available)
+ delete targetChrome.extension.lastError;
+
+ assertRuntimeIsAvailable();
+ delete targetChrome.runtime.lastError;
+ delete privates(targetChrome.runtime).accessedLastError;
+};
+
+function assertRuntimeIsAvailable() {
+ // chrome.runtime should always be available, but maybe it's disappeared for
+ // some reason? Add debugging for http://crbug.com/258526.
+ var runtimeAvailability = GetAvailability('runtime.lastError');
+ if (!runtimeAvailability.is_available) {
+ throw new Error('runtime.lastError is not available: ' +
+ runtimeAvailability.message);
+ }
+ if (!chrome.runtime)
+ throw new Error('runtime namespace is null or undefined');
+}
+
+/**
+ * Runs |callback(args)| with last error args as in set().
+ *
+ * The target chrome object is the global object's of the callback, so this
+ * method won't work if the real callback has been wrapped (etc).
+ */
+function run(name, message, stack, callback, args) {
+ var global = GetGlobal(callback);
+ var targetChrome = global && global.chrome;
+ set(name, message, stack, targetChrome);
+ try {
+ $Function.apply(callback, undefined, args);
+ } finally {
+ reportIfUnchecked(name, targetChrome, stack);
+ clear(targetChrome);
+ }
+}
+
+/**
+ * Checks whether chrome.runtime.lastError has been accessed if set.
+ * If it was set but not accessed, the error is reported to the console.
+ *
+ * @param {string=} name - name of API.
+ * @param {Object} targetChrome - the Chrome object to check.
+ * @param {string=} stack - Stack trace of the call up to the error.
+ */
+function reportIfUnchecked(name, targetChrome, stack) {
+ if (hasAccessed(targetChrome) || !hasError(targetChrome))
+ return;
+ var message = targetChrome.runtime.lastError.message;
+ console.error("Unchecked runtime.lastError while running " +
+ (name || "unknown") + ": " + message + (stack ? "\n" + stack : ""));
+}
+
+exports.$set('clear', clear);
+exports.$set('hasAccessed', hasAccessed);
+exports.$set('hasError', hasError);
+exports.$set('set', set);
+exports.$set('run', run);
+exports.$set('reportIfUnchecked', reportIfUnchecked);