Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 58 additions & 20 deletions src/raven.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ function Raven() {
stackTraceLimit: 50,
autoBreadcrumbs: true,
instrument: true,
sampleRate: 1
sampleRate: 1,
preferFetch: false
};
this._ignoreOnError = 0;
this._isRavenInstalled = false;
Expand Down Expand Up @@ -1232,7 +1233,7 @@ Raven.prototype = {
_window,
'fetch',
function(origFetch) {
return function(fn, t) {
return function() {
// preserve arity
// Make a copy of the arguments to prevent deoptimization
// https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#32-leaking-arguments
Expand All @@ -1256,6 +1257,11 @@ Raven.prototype = {
url = '' + fetchInput;
}

// if Sentry key appears in URL, don't capture
if (url.indexOf(self._globalKey) !== -1) {
return origFetch.apply(this, args);
}

if (args[1] && args[1].method) {
method = args[1].method;
}
Expand Down Expand Up @@ -1675,29 +1681,17 @@ Raven.prototype = {
return true;
},

_setBackoffState: function(request) {
_setBackoffState: function(status, retry) {
// If we are already in a backoff state, don't change anything
if (this._shouldBackoff()) {
return;
}

var status = request.status;

// 400 - project_id doesn't exist or some other fatal
// 401 - invalid/revoked dsn
// 429 - too many requests
if (!(status === 400 || status === 401 || status === 429)) return;

var retry;
try {
// If Retry-After is not in Access-Control-Expose-Headers, most
// browsers will throw an exception trying to access it
retry = request.getResponseHeader('Retry-After');
retry = parseInt(retry, 10) * 1000; // Retry-After is returned in seconds
} catch (e) {
/* eslint no-empty:0 */
}

this._backoffDuration = retry
? // If Sentry server returned a Retry-After value, use it
retry
Expand Down Expand Up @@ -1867,8 +1861,25 @@ Raven.prototype = {
onError: function failure(error) {
self._logDebug('error', 'Raven transport failed to send: ', error);

if (error.request) {
self._setBackoffState(error.request);
if (error.xhrRequest || error.fetchResponse) {
var retry;
var status;
if (error.xhrRequest) {
status = error.xhrRequest.status;
try {
// If Retry-After is not in Access-Control-Expose-Headers, most
// browsers will throw an exception trying to access it
retry = error.xhrRequest.getResponseHeader('Retry-After');
} catch (e) {
/* eslint no-empty:0 */
}
} else if (error.fetchResponse) {
status = error.fetchResponse.status;
if (error.fetchResponse.headers.has('Retry-After')) {
retry = error.fetchResponse.headers.get('Retry-After');
}
}
self._setBackoffState(status, retry && parseInt(retry, 10) * 1000);
}

self._triggerEvent('failure', {
Expand All @@ -1882,9 +1893,36 @@ Raven.prototype = {
},

_makeRequest: function(opts) {
var hasFetch = !!(_window.fetch && _window.Request);
if (this._globalOptions.preferFetch && hasFetch) {
return this._doFetch(opts);
}
var request = _window.XMLHttpRequest && new _window.XMLHttpRequest();
if (!request) return;
if (request) {
return this._doXHR(request, opts);
} else if (hasFetch) {
return this._doFetch(opts);
}
},

_doFetch: function(opts) {
_window
.fetch(opts.url + '?' + urlencode(opts.auth), {
method: 'POST',
body: stringify(opts.data)
})
.then(function(resp) {
if (resp.ok) {
opts.onSuccess && opts.onSuccess();
} else if (opts.onError) {
var err = new Error('Sentry error code: ' + resp.status);
err.fetchResponse = resp;
opts.onError(err);
}
}, opts.onError);
},

_doXHR: function(request, opts) {
// if browser doesn't support CORS (e.g. IE7), we are out of luck
var hasCORS = 'withCredentials' in request || typeof XDomainRequest !== 'undefined';

Expand All @@ -1900,7 +1938,7 @@ Raven.prototype = {
opts.onSuccess && opts.onSuccess();
} else if (opts.onError) {
var err = new Error('Sentry error code: ' + request.status);
err.request = request;
err.xhrRequest = request;
opts.onError(err);
}
};
Expand All @@ -1917,7 +1955,7 @@ Raven.prototype = {
if (opts.onError) {
request.onerror = function() {
var err = new Error('Sentry error code: XDomainRequest');
err.request = request;
err.xhrRequest = request;
opts.onError(err);
};
}
Expand Down
6 changes: 3 additions & 3 deletions test/raven.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1471,7 +1471,7 @@ describe('globals', function() {
Raven._send({message: 'bar'});
var opts = Raven._makeRequest.lastCall.args[0];
var mockError = new Error('429: Too many requests');
mockError.request = {
mockError.xhrRequest = {
status: 429
};
opts.onError(mockError);
Expand Down Expand Up @@ -1502,7 +1502,7 @@ describe('globals', function() {
Raven._send({message: 'bar'});
var opts = Raven._makeRequest.lastCall.args[0];
var mockError = new Error('401: Unauthorized');
mockError.request = {
mockError.xhrRequest = {
status: 401,
getResponseHeader: sinon
.stub()
Expand Down Expand Up @@ -1714,7 +1714,7 @@ describe('globals', function() {
data: {foo: 'bar'},
options: Raven._globalOptions,
onError: function(error) {
assert.equal(error.request.status, 429);
assert.equal(error.xhrRequest.status, 429);
done();
}
});
Expand Down