@@ -31,6 +31,7 @@ function Raven() {
31
31
this . _hasDocument = ! isUndefined ( _document ) ;
32
32
this . _hasNavigator = ! isUndefined ( _navigator ) ;
33
33
this . _lastCapturedException = null ;
34
+ this . _lastData = null ;
34
35
this . _lastEventId = null ;
35
36
this . _globalServer = null ;
36
37
this . _globalKey = null ;
@@ -1334,6 +1335,55 @@ Raven.prototype = {
1334
1335
return this . _backoffDuration && now ( ) - this . _backoffStart < this . _backoffDuration ;
1335
1336
} ,
1336
1337
1338
+ /**
1339
+ * Returns true if the in-process data payload matches the signature
1340
+ * of the previously-sent data
1341
+ *
1342
+ * NOTE: This has to be done at this level because TraceKit can generate
1343
+ * data from window.onerror WITHOUT an exception object (IE8, IE9,
1344
+ * other old browsers). This can take the form of an "exception"
1345
+ * data object with a single frame (derived from the onerror args).
1346
+ */
1347
+ _isRepeatData : function ( current ) {
1348
+ var last = this . _lastData ;
1349
+
1350
+ if ( ! last ||
1351
+ current . message !== last . message ||
1352
+ current . culprit !== last . culprit )
1353
+ return false ;
1354
+
1355
+ // If there's no stacktrace, at this point we consider
1356
+ // them the same event (e.g. captureMessage)
1357
+ if ( ! ( current . exception && last . exception ) )
1358
+ return true ;
1359
+
1360
+ var currentException = current . exception . values [ 0 ] ;
1361
+ var lastException = last . exception . values [ 0 ] ;
1362
+
1363
+ if ( currentException . type !== lastException . type ||
1364
+ currentException . value !== lastException . value )
1365
+ return false ;
1366
+
1367
+ var currentFrames = currentException . stacktrace ;
1368
+ var lastFrames = lastException . stacktrace ;
1369
+
1370
+ if ( currentFrames . length !== lastFrames . length )
1371
+ return false ;
1372
+
1373
+ // Iterate through every frame; bail out if anything differs
1374
+ var a , b ;
1375
+ for ( var i = 0 ; i < currentFrames . length ; i ++ ) {
1376
+ a = currentFrames [ i ] ;
1377
+ b = lastFrames [ i ] ;
1378
+ if ( a . filename !== b . filename ||
1379
+ a . lineno !== b . lineno ||
1380
+ a . colno !== b . colno ||
1381
+ a [ 'function' ] !== b [ 'function' ] )
1382
+ return false ;
1383
+ }
1384
+ return true ;
1385
+ } ,
1386
+
1337
1387
_setBackoffState : function ( request ) {
1338
1388
// If we are already in a backoff state, don't change anything
1339
1389
if ( this . _shouldBackoff ( ) ) {
@@ -1460,6 +1510,14 @@ Raven.prototype = {
1460
1510
// Try and clean up the packet before sending by truncating long values
1461
1511
data = this . _trimPacket ( data ) ;
1462
1512
1513
+ if ( ! this . _globalOptions . allowDuplicates && this . _isRepeatData ( data ) ) {
1514
+ this . _logDebug ( 'warn' , 'Raven dropped repeat event: ' , data ) ;
1515
+ return ;
1516
+ }
1517
+
1518
+ // Store outbound payload after trim
1519
+ this . _lastData = data ;
1520
+
1463
1521
this . _logDebug ( 'debug' , 'Raven about to send:' , data ) ;
1464
1522
1465
1523
var auth = {
0 commit comments