Skip to content

Commit b5e306c

Browse files
committed
fix: Do not override context when capturing non-error exceptions
1 parent 530c258 commit b5e306c

File tree

2 files changed

+88
-14
lines changed

2 files changed

+88
-14
lines changed

lib/client.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,8 @@ extend(Raven.prototype, {
333333
cb = kwargs;
334334
kwargs = {};
335335
} else {
336-
kwargs = kwargs || {};
336+
// Do not use reference, as we'll modify this object later on
337+
kwargs = kwargs ? JSON.parse(stringify(kwargs)) : {};
337338
}
338339

339340
var eventId = this.generateEventId();
@@ -363,25 +364,28 @@ extend(Raven.prototype, {
363364
cb = kwargs;
364365
kwargs = {};
365366
} else {
366-
kwargs = kwargs || {};
367+
var req = kwargs && kwargs.req;
368+
// Do not use reference, as we'll modify this object later on
369+
kwargs = kwargs ? JSON.parse(stringify(kwargs)) : {};
370+
// Preserve `req` so we can use some framework's middleware methods
371+
// `req` is the only thing that we pass through in `errorHandler`, so we need just that
372+
if (req) kwargs.req = req;
367373
}
368374

369375
if (!(err instanceof Error)) {
370376
if (utils.isPlainObject(err)) {
371377
// This will allow us to group events based on top-level keys
372378
// which is much better than creating new group when any key/value change
373379
var keys = Object.keys(err).sort();
374-
var hash = md5(keys);
375380
var message =
376381
'Non-Error exception captured with keys: ' +
377382
utils.serializeKeysForMessage(keys);
378-
var serializedException = utils.serializeException(err);
379-
380-
kwargs.message = message;
381-
kwargs.fingerprint = [hash];
382-
kwargs.extra = {
383-
__serialized__: serializedException
384-
};
383+
kwargs = extend(kwargs, {
384+
message: message,
385+
fingerprint: [md5(keys)],
386+
extra: kwargs.extra || {}
387+
});
388+
kwargs.extra.__serialized__ = utils.serializeException(err);
385389

386390
err = new Error(message);
387391
} else {

test/raven.client.js

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,22 @@ describe('raven.Client', function() {
223223
done();
224224
});
225225
});
226+
227+
it('should copy object with extra data instead of using its reference directly', function(done) {
228+
var old = client.send;
229+
var info = {
230+
extra: {
231+
hello: 'there'
232+
}
233+
};
234+
client.send = function mockSend(kwargs) {
235+
client.send = old;
236+
kwargs.extra.should.have.property('hello', 'there');
237+
kwargs.extra.should.not.equal(info);
238+
done();
239+
};
240+
client.captureMessage('exception', info);
241+
});
226242
});
227243

228244
describe('#captureException()', function() {
@@ -259,13 +275,9 @@ describe('raven.Client', function() {
259275
var old = client.send;
260276
client.send = function mockSend(kwargs) {
261277
client.send = old;
262-
263278
kwargs.message.should.equal(
264279
'Non-Error exception captured with keys: aKeyOne, bKeyTwo, cKeyThree, dKeyFour\u2026'
265280
);
266-
267-
// Remove superfluous node version data to simplify the test itself
268-
delete kwargs.extra.node;
269281
kwargs.extra.should.have.property('__serialized__', {
270282
aKeyOne: 'a',
271283
bKeyTwo: 42,
@@ -385,6 +397,64 @@ describe('raven.Client', function() {
385397
done();
386398
});
387399
});
400+
401+
it('should use and merge provided extra data instead of overriding it', function(done) {
402+
var old = client.send;
403+
client.send = function mockSend(kwargs) {
404+
client.send = old;
405+
kwargs.extra.should.have.property('hello', 'there');
406+
kwargs.tags.should.deepEqual({'0': 'whoop'});
407+
done();
408+
};
409+
client.captureException(
410+
{some: 'exception'},
411+
{
412+
extra: {
413+
hello: 'there'
414+
},
415+
tags: ['whoop']
416+
}
417+
);
418+
});
419+
420+
it('should copy object with extra data instead of using its reference directly', function(done) {
421+
var old = client.send;
422+
var info = {
423+
extra: {
424+
hello: 'there'
425+
}
426+
};
427+
client.send = function mockSend(kwargs) {
428+
client.send = old;
429+
kwargs.extra.should.have.property('hello', 'there');
430+
kwargs.extra.should.not.equal(info.extra);
431+
done();
432+
};
433+
client.captureException({some: 'exception'}, info);
434+
});
435+
436+
it('should preserve same reference to `req` attribute in kwargs', function(done) {
437+
var old = client.process;
438+
var info = {
439+
extra: {
440+
hello: 'there'
441+
},
442+
req: {
443+
something: 'else'
444+
}
445+
};
446+
// Use `process` instead of `send` as `req` is stripped from the final payload
447+
client.process = function mockProcess(id, kwargs) {
448+
client.process = old;
449+
kwargs.extra.should.have.property('hello', 'there');
450+
kwargs.extra.should.not.equal(info.extra);
451+
452+
kwargs.req.should.have.property('something', 'else');
453+
kwargs.req.should.equal(info.req);
454+
done();
455+
};
456+
client.captureException({some: 'exception'}, info);
457+
});
388458
});
389459

390460
describe('#install()', function() {

0 commit comments

Comments
 (0)