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
3// found in the LICENSE file.
4
5var GetAvailability = requireNative('v8_context').GetAvailability;
6var GetGlobal = requireNative('sendRequest').GetGlobal;
7
8// Utility for setting chrome.*.lastError.
9//
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.
16
17/**
18 * Sets the last error for |name| on |targetChrome| to |message| with an
19 * optional |stack|.
20 */
21function set(name, message, stack, targetChrome) {
22  var errorMessage = name + ': ' + message;
23  if (stack != null && stack != '')
24    errorMessage += '\n' + stack;
25
26  if (!targetChrome)
27    throw new Error('No chrome object to set error: ' + errorMessage);
28  clear(targetChrome);  // in case somebody has set a sneaky getter/setter
29
30  var errorObject = { message: message };
31  if (GetAvailability('extension.lastError').is_available)
32    targetChrome.extension.lastError = errorObject;
33
34  assertRuntimeIsAvailable();
35  targetChrome.runtime.lastError = errorObject;
36};
37
38/**
39 * Clears the last error on |targetChrome|.
40 */
41function clear(targetChrome) {
42  if (!targetChrome)
43    throw new Error('No target chrome to clear error');
44
45  if (GetAvailability('extension.lastError').is_available)
46    delete targetChrome.extension.lastError;
47
48  assertRuntimeIsAvailable();
49  delete targetChrome.runtime.lastError;
50};
51
52function assertRuntimeIsAvailable() {
53  // chrome.runtime should always be available, but maybe it's disappeared for
54  // some reason? Add debugging for http://crbug.com/258526.
55  var runtimeAvailability = GetAvailability('runtime.lastError');
56  if (!runtimeAvailability.is_available) {
57    throw new Error('runtime.lastError is not available: ' +
58                    runtimeAvailability.message);
59  }
60  if (!chrome.runtime)
61    throw new Error('runtime namespace is null or undefined');
62}
63
64/**
65 * Runs |callback(args)| with last error args as in set().
66 *
67 * The target chrome object is the global object's of the callback, so this
68 * method won't work if the real callback has been wrapped (etc).
69 */
70function run(name, message, stack, callback, args) {
71  var targetChrome = GetGlobal(callback).chrome;
72  set(name, message, stack, targetChrome);
73  try {
74    $Function.apply(callback, undefined, args);
75  } finally {
76    clear(targetChrome);
77  }
78}
79
80exports.clear = clear;
81exports.set = set;
82exports.run = run;
83