Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / extensions / renderer / resources / uncaught_exception_handler.js
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.
4
5 // Handles uncaught exceptions thrown by extensions. By default this is to
6 // log an error message, but tests may override this behaviour.
7 var handler = function(message, e) {
8   console.error(message);
9 };
10
11 /**
12  * Append the error description and stack trace to |message|.
13  *
14  * @param {string} message - The prefix of the error message.
15  * @param {Error|*} e - The thrown error object. This object is potentially
16  *   unsafe, because it could be generated by an extension.
17  * @param {string=} priorStackTrace - The stack trace to be appended to the
18  *   error message. This stack trace must not include stack frames of |e.stack|,
19  *   because both stack traces are concatenated. Overlapping stack traces will
20  *   confuse extension developers.
21  * @return {string} The formatted error message.
22  */
23 function formatErrorMessage(message, e, priorStackTrace) {
24   if (e)
25     message += ': ' + safeErrorToString(e, false);
26
27   var stack;
28   try {
29     // If the stack was set, use it.
30     // |e.stack| could be void in the following common example:
31     // throw "Error message";
32     stack = $String.self(e && e.stack);
33   } catch (e) {}
34
35   // If a stack is not provided, capture a stack trace.
36   if (!priorStackTrace && !stack)
37     stack = getStackTrace();
38
39   stack = filterExtensionStackTrace(stack);
40   if (stack)
41     message += '\n' + stack;
42
43   // If an asynchronouse stack trace was set, append it.
44   if (priorStackTrace)
45     message += '\n' + priorStackTrace;
46
47   return message;
48 }
49
50 function filterExtensionStackTrace(stack) {
51   if (!stack)
52     return '';
53   // Remove stack frames in the stack trace that weren't associated with the
54   // extension, to not confuse extension developers with internal details.
55   stack = $String.split(stack, '\n');
56   stack = $Array.filter(stack, function(line) {
57     return $String.indexOf(line, 'chrome-extension://') >= 0;
58   });
59   return $Array.join(stack, '\n');
60 }
61
62 function getStackTrace() {
63   var e = {};
64   $Error.captureStackTrace(e, getStackTrace);
65   return e.stack;
66 }
67
68 function getExtensionStackTrace() {
69   return filterExtensionStackTrace(getStackTrace());
70 }
71
72 /**
73  * Convert an object to a string.
74  *
75  * @param {Error|*} e - A thrown object (possibly user-supplied).
76  * @param {boolean=} omitType - Whether to try to serialize |e.message| instead
77  *   of |e.toString()|.
78  * @return {string} The error message.
79  */
80 function safeErrorToString(e, omitType) {
81   try {
82     return $String.self(omitType && e.message || e);
83   } catch (e) {
84     // This error is exceptional and could be triggered by
85     // throw {toString: function() { throw 'Haha' } };
86     return '(cannot get error message)';
87   }
88 }
89
90 /**
91  * Formats the error message and invokes the error handler.
92  *
93  * @param {string} message - Error message prefix.
94  * @param {Error|*} e - Thrown object.
95  * @param {string=} priorStackTrace - Error message suffix.
96  * @see formatErrorMessage
97  */
98 exports.handle = function(message, e, priorStackTrace) {
99   message = formatErrorMessage(message, e, priorStackTrace);
100   handler(message, e);
101 };
102
103 // |newHandler| A function which matches |handler|.
104 exports.setHandler = function(newHandler) {
105   handler = newHandler;
106 };
107
108 exports.getStackTrace = getStackTrace;
109 exports.getExtensionStackTrace = getExtensionStackTrace;
110 exports.safeErrorToString = safeErrorToString;