History

Update raven.js

Thibaut committed 10 years ago

Commit 3b68eb01 parent 5de8c371 file · +336 −152Browse files

Unified · Split

assets/javascripts/vendor/raven.js+336−152
@@ -1,4 +1,4 @@
1−/*! Raven.js 1.1.18 (8ad15bc) | github.com/getsentry/raven-js */
1+/*! Raven.js 1.3.0 (768fdca) | github.com/getsentry/raven-js */
22
33 /*
44 * Includes TraceKit
@@ -21,7 +21,8 @@ var TraceKit = { · 16 unmodified lines
2121 remoteFetching: false,
2222 collectWindowErrors: true,
2323 // 3 lines before, the offending line, 3 lines after
24− linesOfContext: 7
24+ linesOfContext: 7,
25+ debug: false
2526 };
2627
2728 // global reference to slice
@@ -29,23 +30,11 @@ var _slice = [].slice; · 1 unmodified line
2930 var UNKNOWN_FUNCTION = '?';
3031
3132
32−/**
33− * TraceKit.wrap: Wrap any function in a TraceKit reporter
34− * Example: func = TraceKit.wrap(func);
35− *
36− * @param {Function} func Function to be wrapped
37− * @return {Function} The wrapped func
38− */
39−TraceKit.wrap = function traceKitWrapper(func) {
40− function wrapped() {
41− try {
42− return func.apply(this, arguments);
43− } catch (e) {
44− TraceKit.report(e);
45− throw e;
46− }
47− }
48− return wrapped;
33+function getLocationHref() {
34+ if (typeof document === 'undefined')
35+ return '';
36+
37+ return document.location.href;
4938 };
5039
5140 /**
@@ -181,7 +170,7 @@ TraceKit.report = (function reportModuleWrapper() { · 129 unmodified lines
181170 location.context = TraceKit.computeStackTrace.gatherContext(location.url, location.line);
182171 stack = {
183172 'message': message,
184− 'url': document.location.href,
173+ 'url': getLocationHref(),
185174 'stack': [location]
186175 };
187176 notifyHandlers(stack, true);
@@ -319,8 +308,7 @@ TraceKit.report = (function reportModuleWrapper() { · 131 unmodified lines
319308 *
320309 */
321310 TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
322− var debug = false,
323− sourceCache = {};
311+ var sourceCache = {};
324312
325313 /**
326314 * Attempts to retrieve source code via XMLHttpRequest, which is used
@@ -362,7 +350,9 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 35 unmodified lines
362350 // URL needs to be able to fetched within the acceptable domain. Otherwise,
363351 // cross-domain errors will be triggered.
364352 var source = '';
365− if (url.indexOf(document.domain) !== -1) {
353+ var domain = '';
354+ try { domain = document.domain; } catch (e) {}
355+ if (url.indexOf(domain) !== -1) {
366356 source = loadSource(url);
367357 }
368358 sourceCache[url] = source ? source.split('\n') : [];
@@ -524,6 +514,9 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 155 unmodified lines
524514 * the url, line, and column number of the defined function.
525515 */
526516 function findSourceByFunctionBody(func) {
517+ if (typeof document === 'undefined')
518+ return;
519+
527520 var urls = [window.location.href],
528521 scripts = document.getElementsByTagName('script'),
529522 body,
@@ -627,12 +620,11 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 97 unmodified lines
627620 * @return {?Object.<string, *>} Stack trace information.
628621 */
629622 function computeStackTraceFromStackProp(ex) {
630− if (!ex.stack) {
631− return null;
632− }
623+ if (isUndefined(ex.stack) || !ex.stack) return;
633624
634− var chrome = /^\s*at (.*?) ?\(?((?:file|https?|chrome-extension):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
625+ var chrome = /^\s*at (.*?) ?\(?((?:(?:file|https?|chrome-extension):.*?)|<anonymous>):(\d+)(?::(\d+))?\)?\s*$/i,
635626 gecko = /^\s*(.*?)(?:\((.*?)\))?@((?:file|https?|chrome).*?):(\d+)(?::(\d+))?\s*$/i,
627+ winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:ms-appx|http|https):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
636628 lines = ex.stack.split('\n'),
637629 stack = [],
638630 parts,
@@ -655,6 +647,13 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 16 unmodified lines
655647 'line': +parts[3],
656648 'column': parts[4] ? +parts[4] : null
657649 };
650+ } else if ((parts = winjs.exec(lines[i]))) {
651+ element = {
652+ 'url': parts[2],
653+ 'func': parts[1] || UNKNOWN_FUNCTION,
654+ 'line': +parts[3],
655+ 'column': parts[4] ? +parts[4] : null
656+ };
658657 } else {
659658 continue;
660659 }
@@ -686,7 +685,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 25 unmodified lines
686685 return {
687686 'name': ex.name,
688687 'message': ex.message,
689− 'url': document.location.href,
688+ 'url': getLocationHref(),
690689 'stack': stack
691690 };
692691 }
@@ -702,6 +701,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 9 unmodified lines
702701 // else to it because Opera is not very good at providing it
703702 // reliably in other circumstances.
704703 var stacktrace = ex.stacktrace;
704+ if (isUndefined(ex.stacktrace) || !ex.stacktrace) return;
705705
706706 var testRE = / line (\d+), column (\d+) in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\) in (.*):\s*$/i,
707707 lines = stacktrace.split('\n'),
@@ -742,7 +742,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 34 unmodified lines
742742 return {
743743 'name': ex.name,
744744 'message': ex.message,
745− 'url': document.location.href,
745+ 'url': getLocationHref(),
746746 'stack': stack
747747 };
748748 }
@@ -852,7 +852,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 103 unmodified lines
852852 return {
853853 'name': ex.name,
854854 'message': lines[0],
855− 'url': document.location.href,
855+ 'url': getLocationHref(),
856856 'stack': stack
857857 };
858858 }
@@ -951,6 +951,12 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 92 unmodified lines
951951 item.func = parts[1];
952952 }
953953
954+ if (typeof item.func === 'undefined') {
955+ try {
956+ item.func = parts.input.substring(0, parts.input.indexOf('{'));
957+ } catch (e) { }
958+ }
959+
954960 if ((source = findSourceByFunctionBody(curr))) {
955961 item.url = source.url;
956962 item.line = source.line;
@@ -983,7 +989,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 26 unmodified lines
983989 var result = {
984990 'name': ex.name,
985991 'message': ex.message,
986− 'url': document.location.href,
992+ 'url': getLocationHref(),
987993 'stack': stack
988994 };
989995 augmentStackTraceWithInitialElement(result, ex.sourceURL || ex.fileName, ex.line || ex.lineNumber, ex.message || ex.description);
@@ -1008,7 +1014,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 18 unmodified lines
10081014 return stack;
10091015 }
10101016 } catch (e) {
1011− if (debug) {
1017+ if (TraceKit.debug) {
10121018 throw e;
10131019 }
10141020 }
@@ -1019,7 +1025,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 4 unmodified lines
10191025 return stack;
10201026 }
10211027 } catch (e) {
1022− if (debug) {
1028+ if (TraceKit.debug) {
10231029 throw e;
10241030 }
10251031 }
@@ -1030,7 +1036,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 4 unmodified lines
10301036 return stack;
10311037 }
10321038 } catch (e) {
1033− if (debug) {
1039+ if (TraceKit.debug) {
10341040 throw e;
10351041 }
10361042 }
@@ -1041,12 +1047,16 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 4 unmodified lines
10411047 return stack;
10421048 }
10431049 } catch (e) {
1044− if (debug) {
1050+ if (TraceKit.debug) {
10451051 throw e;
10461052 }
10471053 }
10481054
1049− return {};
1055+ return {
1056+ 'name': ex.name,
1057+ 'message': ex.message,
1058+ 'url': getLocationHref()
1059+ };
10501060 }
10511061
10521062 computeStackTrace.augmentStackTraceWithInitialElement = augmentStackTraceWithInitialElement;
@@ -1064,38 +1074,45 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() { · 11 unmodified lines
10641074 // since JSON is required to encode the payload
10651075 var _Raven = window.Raven,
10661076 hasJSON = !!(typeof JSON === 'object' && JSON.stringify),
1077+ // Raven can run in contexts where there's no document (react-native)
1078+ hasDocument = typeof document !== 'undefined',
10671079 lastCapturedException,
10681080 lastEventId,
10691081 globalServer,
1070− globalUser,
10711082 globalKey,
10721083 globalProject,
1084+ globalContext = {},
10731085 globalOptions = {
10741086 logger: 'javascript',
10751087 ignoreErrors: [],
10761088 ignoreUrls: [],
10771089 whitelistUrls: [],
10781090 includePaths: [],
1091+ crossOrigin: 'anonymous',
10791092 collectWindowErrors: true,
1080− tags: {},
1081− maxMessageLength: 100,
1082− extra: {}
1093+ maxMessageLength: 100
10831094 },
1084− authQueryString,
10851095 isRavenInstalled = false,
1086−
10871096 objectPrototype = Object.prototype,
1097+ // capture references to window.console *and* all its methods first
1098+ // before the console plugin has a chance to monkey patch
1099+ originalConsole = window.console || {},
1100+ originalConsoleMethods = {},
1101+ plugins = [],
10881102 startTime = now();
10891103
1104+for (var method in originalConsole) {
1105+ originalConsoleMethods[method] = originalConsole[method];
1106+}
10901107 /*
10911108 * The core Raven singleton
10921109 *
10931110 * @this {Raven}
10941111 */
10951112 var Raven = {
1096− VERSION: '1.1.18',
1113+ VERSION: '1.3.0',
10971114
1098− debug: true,
1115+ debug: false,
10991116
11001117 /*
11011118 * Allow multiple versions of Raven to be installed.
@@ -1129,7 +1146,12 @@ var Raven = { · 27 unmodified lines
11291146 // merge in options
11301147 if (options) {
11311148 each(options, function(key, value){
1132− globalOptions[key] = value;
1149+ // tags and extra are special and need to be put into context
1150+ if (key == 'tags' || key == 'extra') {
1151+ globalContext[key] = value;
1152+ } else {
1153+ globalOptions[key] = value;
1154+ }
11331155 });
11341156 }
11351157
@@ -1166,8 +1188,6 @@ var Raven = { · 30 unmodified lines
11661188
11671189 TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors;
11681190
1169− setAuthQueryString();
1170−
11711191 // return for chaining
11721192 return Raven;
11731193 },
@@ -1183,6 +1203,12 @@ var Raven = { · 9 unmodified lines
11831203 install: function() {
11841204 if (isSetup() && !isRavenInstalled) {
11851205 TraceKit.report.subscribe(handleStackInfo);
1206+
1207+ // Install all of the plugins
1208+ each(plugins, function(_, plugin) {
1209+ plugin();
1210+ });
1211+
11861212 isRavenInstalled = true;
11871213 }
11881214
@@ -1261,6 +1287,7 @@ var Raven = { · 72 unmodified lines
12611287 wrapped[property] = func[property];
12621288 }
12631289 }
1290+ wrapped.prototype = func.prototype;
12641291
12651292 // Signal that this function has been wrapped already
12661293 // for both debugging and to prevent it to being wrapped twice
@@ -1302,7 +1329,8 @@ var Raven = { · 35 unmodified lines
13021329 // raises an exception different from the one we asked to
13031330 // report on.
13041331 try {
1305− TraceKit.report(ex, options);
1332+ var stack = TraceKit.computeStackTrace(ex);
1333+ handleStackInfo(stack, options);
13061334 } catch(ex1) {
13071335 if(ex !== ex1) {
13081336 throw ex1;
@@ -1337,6 +1365,12 @@ var Raven = { · 28 unmodified lines
13371365 return Raven;
13381366 },
13391367
1368+ addPlugin: function(plugin) {
1369+ plugins.push(plugin);
1370+ if (isRavenInstalled) plugin();
1371+ return Raven;
1372+ },
1373+
13401374 /*
13411375 * Set/clear a user to be sent along with the payload.
13421376 *
@@ -1344,47 +1378,110 @@ var Raven = { · 1 unmodified line
13441378 * @return {Raven}
13451379 */
13461380 setUserContext: function(user) {
1347− globalUser = user;
1381+ // Intentionally do not merge here since that's an unexpected behavior.
1382+ globalContext.user = user;
13481383
13491384 return Raven;
13501385 },
13511386
13521387 /*
1353− * Set extra attributes to be sent along with the payload.
1388+ * Merge extra attributes to be sent along with the payload.
13541389 *
13551390 * @param {object} extra An object representing extra data [optional]
13561391 * @return {Raven}
13571392 */
13581393 setExtraContext: function(extra) {
1359− globalOptions.extra = extra || {};
1394+ mergeContext('extra', extra);
13601395
13611396 return Raven;
13621397 },
13631398
13641399 /*
1365− * Set tags to be sent along with the payload.
1400+ * Merge tags to be sent along with the payload.
13661401 *
13671402 * @param {object} tags An object representing tags [optional]
13681403 * @return {Raven}
13691404 */
13701405 setTagsContext: function(tags) {
1371− globalOptions.tags = tags || {};
1406+ mergeContext('tags', tags);
13721407
13731408 return Raven;
13741409 },
13751410
1411+ /*
1412+ * Clear all of the context.
1413+ *
1414+ * @return {Raven}
1415+ */
1416+ clearContext: function() {
1417+ globalContext = {};
1418+
1419+ return Raven;
1420+ },
1421+
1422+ /*
1423+ * Get a copy of the current context. This cannot be mutated.
1424+ *
1425+ * @return {object} copy of context
1426+ */
1427+ getContext: function() {
1428+ // lol javascript
1429+ return JSON.parse(JSON.stringify(globalContext));
1430+ },
1431+
13761432 /*
13771433 * Set release version of application
13781434 *
13791435 * @param {string} release Typically something like a git SHA to identify version
13801436 * @return {Raven}
13811437 */
1382− setReleaseContext: function(release) {
1438+ setRelease: function(release) {
13831439 globalOptions.release = release;
13841440
13851441 return Raven;
13861442 },
13871443
1444+ /*
1445+ * Set the dataCallback option
1446+ *
1447+ * @param {function} callback The callback to run which allows the
1448+ * data blob to be mutated before sending
1449+ * @return {Raven}
1450+ */
1451+ setDataCallback: function(callback) {
1452+ globalOptions.dataCallback = callback;
1453+
1454+ return Raven;
1455+ },
1456+
1457+ /*
1458+ * Set the shouldSendCallback option
1459+ *
1460+ * @param {function} callback The callback to run which allows
1461+ * introspecting the blob before sending
1462+ * @return {Raven}
1463+ */
1464+ setShouldSendCallback: function(callback) {
1465+ globalOptions.shouldSendCallback = callback;
1466+
1467+ return Raven;
1468+ },
1469+
1470+ /**
1471+ * Override the default HTTP transport mechanism that transmits data
1472+ * to the Sentry server.
1473+ *
1474+ * @param {function} transport Function invoked instead of the default
1475+ * `makeRequest` handler.
1476+ *
1477+ * @return {Raven}
1478+ */
1479+ setTransport: function(transport) {
1480+ globalOptions.transport = transport;
1481+
1482+ return Raven;
1483+ },
1484+
13881485 /*
13891486 * Get the latest raw exception that was captured by Raven.
13901487 *
@@ -1413,41 +1510,47 @@ var Raven = { · 22 unmodified lines
14131510 }
14141511 };
14151512
1416−Raven.setUser = Raven.setUserContext; // To be deprecated
1513+// Deprecations
1514+Raven.setUser = Raven.setUserContext;
1515+Raven.setReleaseContext = Raven.setRelease;
14171516
14181517 function triggerEvent(eventType, options) {
1419− var event, key;
1518+ // NOTE: `event` is a native browser thing, so let's avoid conflicting wiht it
1519+ var evt, key;
1520+
1521+ if (!hasDocument)
1522+ return;
14201523
14211524 options = options || {};
14221525
14231526 eventType = 'raven' + eventType.substr(0,1).toUpperCase() + eventType.substr(1);
14241527
14251528 if (document.createEvent) {
1426− event = document.createEvent('HTMLEvents');
1427− event.initEvent(eventType, true, true);
1529+ evt = document.createEvent('HTMLEvents');
1530+ evt.initEvent(eventType, true, true);
14281531 } else {
1429− event = document.createEventObject();
1430− event.eventType = eventType;
1532+ evt = document.createEventObject();
1533+ evt.eventType = eventType;
14311534 }
14321535
14331536 for (key in options) if (hasKey(options, key)) {
1434− event[key] = options[key];
1537+ evt[key] = options[key];
14351538 }
14361539
14371540 if (document.createEvent) {
14381541 // IE9 if standards
1439− document.dispatchEvent(event);
1542+ document.dispatchEvent(evt);
14401543 } else {
14411544 // IE8 regardless of Quirks or Standards
14421545 // IE9 if quirks
14431546 try {
1444− document.fireEvent('on' + event.eventType.toLowerCase(), event);
1547+ document.fireEvent('on' + evt.eventType.toLowerCase(), evt);
14451548 } catch(e) {}
14461549 }
14471550 }
14481551
14491552 var dsnKeys = 'source protocol user pass host port path'.split(' '),
1450− dsnPattern = /^(?:(\w+):)?\/\/(\w+)(:\w+)?@([\w\.-]+)(?::(\d+))?(\/.*)/;
1553+ dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
14511554
14521555 function RavenConfigError(message) {
14531556 this.name = 'RavenConfigError';
@@ -1475,7 +1578,7 @@ function parseDSN(str) { · 21 unmodified lines
14751578 }
14761579
14771580 function isUndefined(what) {
1478− return typeof what === 'undefined';
1581+ return what === void 0;
14791582 }
14801583
14811584 function isFunction(what) {
@@ -1483,7 +1586,7 @@ function isFunction(what) { · 1 unmodified line
14831586 }
14841587
14851588 function isString(what) {
1486− return typeof what === 'string';
1589+ return objectPrototype.toString.call(what) === '[object String]';
14871590 }
14881591
14891592 function isObject(what) {
@@ -1533,15 +1636,6 @@ function each(obj, callback) { · 43 unmodified lines
15331636 }
15341637 }
15351638
1536−
1537−function setAuthQueryString() {
1538− authQueryString =
1539− '?sentry_version=4' +
1540− '&sentry_client=raven-js/' + Raven.VERSION +
1541− '&sentry_key=' + globalKey;
1542−}
1543−
1544−
15451639 function handleStackInfo(stackInfo, options) {
15461640 var frames = [];
15471641
@@ -1588,7 +1682,7 @@ function normalizeFrame(frame) { · 40 unmodified lines
15881682
15891683 normalized.in_app = !( // determine if an exception came from outside of our app
15901684 // first we check the global includePaths list.
1591− !globalOptions.includePaths.test(normalized.filename) ||
1685+ (!!globalOptions.includePaths.test && !globalOptions.includePaths.test(normalized.filename)) ||
15921686 // Now we check for fun, if the function name is Raven or TraceKit
15931687 /(Raven|TraceKit)\./.test(normalized['function']) ||
15941688 // finally, we do a last ditch effort and check for raven.min.js
@@ -1638,20 +1732,12 @@ function extractContextFromFrame(frame) { · 43 unmodified lines
16381732 }
16391733
16401734 function processException(type, message, fileurl, lineno, frames, options) {
1641− var stacktrace, label, i;
1735+ var stacktrace, i, fullMessage;
16421736
1643− // In some instances message is not actually a string, no idea why,
1644− // so we want to always coerce it to one.
1645− message += '';
1646−
1647− // Sometimes an exception is getting logged in Sentry as
1648− // <no message value>
1649− // This can only mean that the message was falsey since this value
1650− // is hardcoded into Sentry itself.
1651− // At this point, if the message is falsey, we bail since it's useless
1652− if (type === 'Error' && !message) return;
1737+ if (!!globalOptions.ignoreErrors.test && globalOptions.ignoreErrors.test(message)) return;
16531738
1654− if (globalOptions.ignoreErrors.test(message)) return;
1739+ message += '';
1740+ fullMessage = type + ': ' + message;
16551741
16561742 if (frames && frames.length) {
16571743 fileurl = frames[0].filename || fileurl;
@@ -1669,26 +1755,22 @@ function processException(type, message, fileurl, lineno, frames, options) { · 11 unmodified lines
16691755 };
16701756 }
16711757
1672− // Truncate the message to a max of characters
1673− message = truncate(message, globalOptions.maxMessageLength);
1674−
1675− if (globalOptions.ignoreUrls && globalOptions.ignoreUrls.test(fileurl)) return;
1676− if (globalOptions.whitelistUrls && !globalOptions.whitelistUrls.test(fileurl)) return;
1677−
1678− label = lineno ? message + ' at ' + lineno : message;
1758+ if (!!globalOptions.ignoreUrls.test && globalOptions.ignoreUrls.test(fileurl)) return;
1759+ if (!!globalOptions.whitelistUrls.test && !globalOptions.whitelistUrls.test(fileurl)) return;
16791760
16801761 // Fire away!
16811762 send(
16821763 objectMerge({
16831764 // sentry.interfaces.Exception
16841765 exception: {
1685− type: type,
1686− value: message
1766+ values: [{
1767+ type: type,
1768+ value: message,
1769+ stacktrace: stacktrace
1770+ }]
16871771 },
1688− // sentry.interfaces.Stacktrace
1689− stacktrace: stacktrace,
16901772 culprit: fileurl,
1691− message: label
1773+ message: fullMessage
16921774 }, options)
16931775 );
16941776 }
@@ -1707,58 +1789,83 @@ function truncate(str, max) { · 12 unmodified lines
17071789 return str.length <= max ? str : str.substr(0, max) + '\u2026';
17081790 }
17091791
1792+function trimPacket(data) {
1793+ // For now, we only want to truncate the two different messages
1794+ // but this could/should be expanded to just trim everything
1795+ var max = globalOptions.maxMessageLength;
1796+ data.message = truncate(data.message, max);
1797+ if (data.exception) {
1798+ var exception = data.exception.values[0];
1799+ exception.value = truncate(exception.value, max);
1800+ }
1801+
1802+ return data;
1803+}
1804+
17101805 function now() {
17111806 return +new Date();
17121807 }
17131808
17141809 function getHttpData() {
1715− var http = {
1716− url: document.location.href,
1810+ if (!hasDocument || !document.location || !document.location.href) {
1811+ return;
1812+ }
1813+
1814+ var httpData = {
17171815 headers: {
17181816 'User-Agent': navigator.userAgent
17191817 }
17201818 };
17211819
1820+ httpData.url = document.location.href;
1821+
17221822 if (document.referrer) {
1723− http.headers.Referer = document.referrer;
1823+ httpData.headers.Referer = document.referrer;
17241824 }
17251825
1726− return http;
1826+ return httpData;
17271827 }
17281828
17291829 function send(data) {
1730− if (!isSetup()) return;
1731−
1732− data = objectMerge({
1830+ var baseData = {
17331831 project: globalProject,
17341832 logger: globalOptions.logger,
1735− platform: 'javascript',
1736− // sentry.interfaces.Http
1737− request: getHttpData()
1738− }, data);
1833+ platform: 'javascript'
1834+ }, httpData = getHttpData();
1835+
1836+ if (httpData) {
1837+ baseData.request = httpData;
1838+ }
1839+
1840+ data = objectMerge(baseData, data);
17391841
17401842 // Merge in the tags and extra separately since objectMerge doesn't handle a deep merge
1741− data.tags = objectMerge(objectMerge({}, globalOptions.tags), data.tags);
1742− data.extra = objectMerge(objectMerge({}, globalOptions.extra), data.extra);
1843+ data.tags = objectMerge(objectMerge({}, globalContext.tags), data.tags);
1844+ data.extra = objectMerge(objectMerge({}, globalContext.extra), data.extra);
17431845
17441846 // Send along our own collected metadata with extra
1745− data.extra = objectMerge({
1746− 'session:duration': now() - startTime
1747− }, data.extra);
1847+ data.extra['session:duration'] = now() - startTime;
17481848
17491849 // If there are no tags/extra, strip the key from the payload alltogther.
17501850 if (isEmptyObject(data.tags)) delete data.tags;
17511851
1752− if (globalUser) {
1852+ if (globalContext.user) {
17531853 // sentry.interfaces.User
1754− data.user = globalUser;
1854+ data.user = globalContext.user;
17551855 }
17561856
1757− // Include the release iff it's defined in globalOptions
1857+ // Include the release if it's defined in globalOptions
17581858 if (globalOptions.release) data.release = globalOptions.release;
1859+ // Include server_name if it's defined in globalOptions
1860+ if (globalOptions.serverName) data.server_name = globalOptions.serverName;
17591861
17601862 if (isFunction(globalOptions.dataCallback)) {
1761− data = globalOptions.dataCallback(data);
1863+ data = globalOptions.dataCallback(data) || data;
1864+ }
1865+
1866+ // Why??????????
1867+ if (!data || isEmptyObject(data)) {
1868+ return;
17621869 }
17631870
17641871 // Check if the request should be filtered or not
@@ -1771,34 +1878,68 @@ function send(data) { · 6 unmodified lines
17711878 // Set lastEventId after we know the error should actually be sent
17721879 lastEventId = data.event_id || (data.event_id = uuid4());
17731880
1774− makeRequest(data);
1881+ // Try and clean up the packet before sending by truncating long values
1882+ data = trimPacket(data);
1883+
1884+ logDebug('debug', 'Raven about to send:', data);
1885+
1886+ if (!isSetup()) return;
1887+
1888+ (globalOptions.transport || makeRequest)({
1889+ url: globalServer,
1890+ auth: {
1891+ sentry_version: '7',
1892+ sentry_client: 'raven-js/' + Raven.VERSION,
1893+ sentry_key: globalKey
1894+ },
1895+ data: data,
1896+ options: globalOptions,
1897+ onSuccess: function success() {
1898+ triggerEvent('success', {
1899+ data: data,
1900+ src: globalServer
1901+ });
1902+ },
1903+ onError: function failure() {
1904+ triggerEvent('failure', {
1905+ data: data,
1906+ src: globalServer
1907+ });
1908+ }
1909+ });
17751910 }
17761911
1912+function makeRequest(opts) {
1913+ // Tack on sentry_data to auth options, which get urlencoded
1914+ opts.auth.sentry_data = JSON.stringify(opts.data);
17771915
1778−function makeRequest(data) {
1779− var img = new Image(),
1780− src = globalServer + authQueryString + '&sentry_data=' + encodeURIComponent(JSON.stringify(data));
1916+ var img = newImage(),
1917+ src = opts.url + '?' + urlencode(opts.auth),
1918+ crossOrigin = opts.options.crossOrigin;
17811919
1782− img.crossOrigin = 'anonymous';
1783− img.onload = function success() {
1784− triggerEvent('success', {
1785− data: data,
1786− src: src
1787− });
1788− };
1789− img.onerror = img.onabort = function failure() {
1790− triggerEvent('failure', {
1791− data: data,
1792− src: src
1793− });
1794− };
1920+ if (crossOrigin || crossOrigin === '') {
1921+ img.crossOrigin = crossOrigin;
1922+ }
1923+ img.onload = opts.onSuccess;
1924+ img.onerror = img.onabort = opts.onError;
17951925 img.src = src;
17961926 }
17971927
1928+// Note: this is shitty, but I can't figure out how to get
1929+// sinon to stub document.createElement without breaking everything
1930+// so this wrapper is just so I can stub it for tests.
1931+function newImage() {
1932+ return document.createElement('img');
1933+}
1934+
1935+var ravenNotConfiguredError;
1936+
17981937 function isSetup() {
17991938 if (!hasJSON) return false; // needs JSON support
18001939 if (!globalServer) {
1801− logDebug('error', 'Error: Raven has not been configured.');
1940+ if (!ravenNotConfiguredError)
1941+ logDebug('error', 'Error: Raven has not been configured.');
1942+ ravenNotConfiguredError = true;
18021943 return false;
18031944 }
18041945 return true;
@@ -1826,18 +1967,44 @@ function joinRegExp(patterns) { · 21 unmodified lines
18261967 return new RegExp(sources.join('|'), 'i');
18271968 }
18281969
1829−// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
18301970 function uuid4() {
1831− return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
1832− var r = Math.random()*16|0,
1833− v = c == 'x' ? r : (r&0x3|0x8);
1834− return v.toString(16);
1835− });
1971+ var crypto = window.crypto || window.msCrypto;
1972+
1973+ if (!isUndefined(crypto) && crypto.getRandomValues) {
1974+ // Use window.crypto API if available
1975+ var arr = new Uint16Array(8);
1976+ crypto.getRandomValues(arr);
1977+
1978+ // set 4 in byte 7
1979+ arr[3] = arr[3] & 0xFFF | 0x4000;
1980+ // set 2 most significant bits of byte 9 to '10'
1981+ arr[4] = arr[4] & 0x3FFF | 0x8000;
1982+
1983+ var pad = function(num) {
1984+ var v = num.toString(16);
1985+ while (v.length < 4) {
1986+ v = '0' + v;
1987+ }
1988+ return v;
1989+ };
1990+
1991+ return (pad(arr[0]) + pad(arr[1]) + pad(arr[2]) + pad(arr[3]) + pad(arr[4]) +
1992+ pad(arr[5]) + pad(arr[6]) + pad(arr[7]));
1993+ } else {
1994+ // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
1995+ return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
1996+ var r = Math.random()*16|0,
1997+ v = c == 'x' ? r : (r&0x3|0x8);
1998+ return v.toString(16);
1999+ });
2000+ }
18362001 }
18372002
1838−function logDebug(level, message) {
1839− if (window.console && console[level] && Raven.debug) {
1840− console[level](message);
2003+function logDebug(level) {
2004+ if (originalConsoleMethods[level] && Raven.debug) {
2005+ // _slice is coming from vendor/TraceKit/tracekit.js
2006+ // so it's accessible globally
2007+ originalConsoleMethods[level].apply(originalConsole, _slice.call(arguments, 1));
18412008 }
18422009 }
18432010
@@ -1848,12 +2015,32 @@ function afterLoad() { · 4 unmodified lines
18482015 Raven.config(RavenConfig.dsn, RavenConfig.config).install();
18492016 }
18502017 }
2018+
2019+function urlencode(o) {
2020+ var pairs = [];
2021+ each(o, function(key, value) {
2022+ pairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
2023+ });
2024+ return pairs.join('&');
2025+}
2026+
2027+function mergeContext(key, context) {
2028+ if (isUndefined(context)) {
2029+ delete globalContext[key];
2030+ } else {
2031+ globalContext[key] = objectMerge(globalContext[key] || {}, context);
2032+ }
2033+}
2034+
18512035 afterLoad();
18522036
2037+// This is being exposed no matter what because there are too many weird
2038+// usecases for how people use Raven. If this is really a problem, I'm sorry.
2039+window.Raven = Raven;
2040+
18532041 // Expose Raven to the world
18542042 if (typeof define === 'function' && define.amd) {
18552043 // AMD
1856− window.Raven = Raven;
18572044 define('raven', [], function() {
18582045 return Raven;
18592046 });
@@ -1863,9 +2050,6 @@ if (typeof define === 'function' && define.amd) { · 3 unmodified lines
18632050 } else if (typeof exports === 'object') {
18642051 // CommonJS
18652052 exports = Raven;
1866−} else {
1867− // Everything else
1868− window.Raven = Raven;
18692053 }
18702054
1871−})(window);
2055+})(typeof window !== 'undefined' ? window : this);