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
6 changes: 6 additions & 0 deletions docs/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ Those configuration options are documented below:
onFailure
Callback to be invoked upon a failed request.

.. describe:: timeout

By default, Raven.js requests do not time out. By setting this options, you can enforce that the request
is aborted after a number of milliseconds, e.g. set ``timeout: 500`` to abort after half a second during
configuration. Once the timeout occurs, the ``ravenTimeout`` event is triggered.

.. describe:: allowSecretKey

By default, Raven.js will throw an error if configured with a Sentry DSN that contains a secret key.
Expand Down
14 changes: 11 additions & 3 deletions src/raven.js
Original file line number Diff line number Diff line change
Expand Up @@ -1039,9 +1039,10 @@ Raven.prototype = {
},

_makeXhrRequest: function(opts) {
var request;
var request,
self = this,
url = opts.url;

var url = opts.url;
function handler() {
if (request.status === 200) {
if (opts.onSuccess) {
Expand Down Expand Up @@ -1070,6 +1071,13 @@ Raven.prototype = {
request.onload = handler;
}

// Allow limiting request duration to ensure that logging something will always reach a finished state. By
// default, the timeout is 0, which is unlimited.
request.timeout = opts.options.timeout || 0;
request.ontimeout = function () {
self._triggerEvent('timeout');
};

// NOTE: auth is intentionally sent as part of query string (NOT as custom
// HTTP header) so as to avoid preflight CORS requests
request.open('POST', url + '?' + urlencode(opts.auth));
Expand All @@ -1081,7 +1089,7 @@ Raven.prototype = {
'withCredentials' in new XMLHttpRequest() ||
typeof XDomainRequest !== 'undefined';

return (hasCORS ? this._makeXhrRequest : this._makeImageRequest)(opts);
return (hasCORS ? this._makeXhrRequest : this._makeImageRequest).call(this, opts);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops

},

// Note: this is shitty, but I can't figure out how to get
Expand Down
44 changes: 44 additions & 0 deletions test/raven.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,50 @@ describe('globals', function() {
assert.equal(lastXhr.requestBody, '{"foo":"bar"}');
assert.equal(lastXhr.url, 'http://localhost/?a=1&b=2');
});

it('should set the request timeout if configured', function() {
var optionsWithTimeout = JSON.parse(JSON.stringify(Raven._globalOptions)),
expectedTimeout = 500;

optionsWithTimeout.timeout = expectedTimeout;
Raven._makeXhrRequest({
url: 'http://localhost/',
auth: {a: '1', b: '2'},
data: {foo: 'bar'},
options: optionsWithTimeout
});

var lastXhr = this.requests[this.requests.length - 1];
assert.equal(lastXhr.timeout, expectedTimeout);
});

it('should trigger a timeout event once timeout occurs', function () {
Raven._makeXhrRequest({
url: 'http://localhost/',
auth: {a: '1', b: '2'},
data: {foo: 'bar'},
options: Raven._globalOptions
});
this.sinon.stub(Raven, '_triggerEvent');

var lastXhr = this.requests[this.requests.length - 1];
assert.typeOf(lastXhr.ontimeout, 'function');

lastXhr.ontimeout();
assert.isTrue(Raven._triggerEvent.calledWith('timeout'));
});

it('should use an infinite request timeout by default', function() {
Raven._makeXhrRequest({
url: 'http://localhost/',
auth: {a: '1', b: '2'},
data: {foo: 'bar'},
options: Raven._globalOptions
});

var lastXhr = this.requests[this.requests.length - 1];
assert.equal(lastXhr.timeout, 0);
});
});

describe('makeImageRequest', function() {
Expand Down