Skip to content

Commit d1050ce

Browse files
committed
Merge pull request #550 from getsentry/xhr-breadcrumb-bug
Fix XHR breadcrumbs not captured when no onreadystatechange handler set
2 parents 2e21555 + ba3c46d commit d1050ce

File tree

2 files changed

+58
-9
lines changed

2 files changed

+58
-9
lines changed

src/raven.js

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -742,21 +742,36 @@ Raven.prototype = {
742742
fill(xhrproto, 'send', function(origSend) {
743743
return function (data) { // preserve arity
744744
var xhr = this;
745-
'onreadystatechange onload onerror onprogress'.replace(/\w+/g, function (prop) {
745+
746+
function onreadystatechangeHandler() {
747+
if (xhr.__raven_xhr && (xhr.readyState === 1 || xhr.readyState === 4)) {
748+
try {
749+
// touching statusCode in some platforms throws
750+
// an exception
751+
xhr.__raven_xhr.status_code = xhr.status;
752+
} catch (e) { /* do nothing */ }
753+
self.captureBreadcrumb('http_request', xhr.__raven_xhr);
754+
}
755+
}
756+
757+
'onload onerror onprogress'.replace(/\w+/g, function (prop) {
746758
if (prop in xhr && isFunction(xhr[prop])) {
747759
fill(xhr, prop, function (orig) {
748-
if (prop === 'onreadystatechange' && xhr.__raven_xhr && (xhr.readyState === 1 || xhr.readyState === 4)) {
749-
try {
750-
// touching statusCode in some platforms throws
751-
// an exception
752-
xhr.__raven_xhr.status_code = xhr.status;
753-
} catch (e) { /* do nothing */ }
754-
self.captureBreadcrumb('http_request', xhr.__raven_xhr);
755-
}
756760
return self.wrap(orig);
757761
}, true /* noUndo */); // don't track filled methods on XHR instances
758762
}
759763
});
764+
765+
if ('onreadystatechange' in xhr && isFunction(xhr.onreadystatechange)) {
766+
fill(xhr, 'onreadystatechange', function (orig) {
767+
return self.wrap(orig, undefined, onreadystatechangeHandler);
768+
}, true /* noUndo */);
769+
} else {
770+
// if onreadystatechange wasn't actually set by the page on this xhr, we
771+
// are free to set our own and capture the breadcrumb
772+
xhr.onreadystatechange = onreadystatechangeHandler;
773+
}
774+
760775
return origSend.apply(this, arguments);
761776
};
762777
});

test/integration/test.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,40 @@ describe('integration', function () {
338338
);
339339
});
340340

341+
it('should record an XMLHttpRequest without any handlers set', function (done) {
342+
var iframe = this.iframe;
343+
344+
iframeExecute(iframe, done,
345+
function () {
346+
// I hate to do a time-based "done" trigger, but unfortunately we can't
347+
// set an onload/onreadystatechange handler on XHR to verify that it finished
348+
// - that's the whole point of this test! :(
349+
setTimeout(done, 1000);
350+
351+
// some browsers trigger onpopstate for load / reset breadcrumb state
352+
Raven._breadcrumbs = [];
353+
354+
var xhr = new XMLHttpRequest();
355+
356+
xhr.open('GET', '/test/integration/example.json');
357+
xhr.setRequestHeader('Content-type', 'application/json');
358+
xhr.send();
359+
},
360+
function () {
361+
var Raven = iframe.contentWindow.Raven,
362+
breadcrumbs = Raven._breadcrumbs;
363+
364+
assert.equal(breadcrumbs.length, 1);
365+
366+
assert.equal(breadcrumbs[0].type, 'http_request');
367+
assert.equal(breadcrumbs[0].data.method, 'GET');
368+
// NOTE: not checking status code because we seem to get
369+
// statusCode 0/undefined from Phantom when fetching
370+
// example.json (CORS issue?
371+
}
372+
);
373+
});
374+
341375
it('should record a mouse click on element WITH click handler present', function (done) {
342376
var iframe = this.iframe;
343377

0 commit comments

Comments
 (0)