rollbar 2.25.1 → 2.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rollbar.js +261 -61
- package/dist/rollbar.js.map +1 -1
- package/dist/rollbar.min.js +1 -1
- package/dist/rollbar.min.js.map +1 -1
- package/dist/rollbar.named-amd.js +261 -61
- package/dist/rollbar.named-amd.js.map +1 -1
- package/dist/rollbar.named-amd.min.js +1 -1
- package/dist/rollbar.named-amd.min.js.map +1 -1
- package/dist/rollbar.noconflict.umd.js +261 -61
- package/dist/rollbar.noconflict.umd.js.map +1 -1
- package/dist/rollbar.noconflict.umd.min.js +1 -1
- package/dist/rollbar.noconflict.umd.min.js.map +1 -1
- package/dist/rollbar.snippet.js +1 -1
- package/dist/rollbar.umd.js +261 -61
- package/dist/rollbar.umd.js.map +1 -1
- package/dist/rollbar.umd.min.js +1 -1
- package/dist/rollbar.umd.min.js.map +1 -1
- package/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/apiUtility.js +14 -2
- package/src/browser/telemetry.js +6 -1
- package/src/browser/transforms.js +12 -7
- package/src/browser/transport/fetch.js +35 -0
- package/src/browser/transport/xhr.js +159 -0
- package/src/browser/transport.js +29 -166
- package/src/defaults.js +1 -1
- package/src/utility/headers.js +94 -0
- package/test/apiUtility.test.js +54 -0
- package/test/browser.rollbar.test.js +101 -28
- package/test/browser.transforms.test.js +15 -1
- package/test/browser.transport.test.js +59 -0
package/index.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ declare namespace Rollbar {
|
|
|
75
75
|
hostBlockList?: string[];
|
|
76
76
|
hostWhiteList?: string[]; // deprecated
|
|
77
77
|
hostSafeList?: string[];
|
|
78
|
-
ignoredMessages?: string[];
|
|
78
|
+
ignoredMessages?: (string | RegExp)[];
|
|
79
79
|
ignoreDuplicateErrors?: boolean;
|
|
80
80
|
includeItemsInTelemetry?: boolean;
|
|
81
81
|
inspectAnonymousErrors?: boolean;
|
package/package.json
CHANGED
package/src/apiUtility.js
CHANGED
|
@@ -25,6 +25,7 @@ function getTransportFromOptions(options, defaults, url) {
|
|
|
25
25
|
var path = defaults.path;
|
|
26
26
|
var search = defaults.search;
|
|
27
27
|
var timeout = options.timeout;
|
|
28
|
+
var transport = detectTransport(options)
|
|
28
29
|
|
|
29
30
|
var proxy = options.proxy;
|
|
30
31
|
if (options.endpoint) {
|
|
@@ -42,16 +43,26 @@ function getTransportFromOptions(options, defaults, url) {
|
|
|
42
43
|
port: port,
|
|
43
44
|
path: path,
|
|
44
45
|
search: search,
|
|
45
|
-
proxy: proxy
|
|
46
|
+
proxy: proxy,
|
|
47
|
+
transport: transport
|
|
46
48
|
};
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
function detectTransport(options) {
|
|
52
|
+
var gWindow = ((typeof window != 'undefined') && window) || ((typeof self != 'undefined') && self);
|
|
53
|
+
var transport = options.defaultTransport || 'xhr';
|
|
54
|
+
if (typeof gWindow.fetch === 'undefined') transport = 'xhr';
|
|
55
|
+
if (typeof gWindow.XMLHttpRequest === 'undefined') transport = 'fetch';
|
|
56
|
+
return transport;
|
|
57
|
+
}
|
|
58
|
+
|
|
49
59
|
function transportOptions(transport, method) {
|
|
50
60
|
var protocol = transport.protocol || 'https:';
|
|
51
61
|
var port = transport.port || (protocol === 'http:' ? 80 : protocol === 'https:' ? 443 : undefined);
|
|
52
62
|
var hostname = transport.hostname;
|
|
53
63
|
var path = transport.path;
|
|
54
64
|
var timeout = transport.timeout;
|
|
65
|
+
var transportAPI = transport.transport;
|
|
55
66
|
if (transport.search) {
|
|
56
67
|
path = path + transport.search;
|
|
57
68
|
}
|
|
@@ -67,7 +78,8 @@ function transportOptions(transport, method) {
|
|
|
67
78
|
hostname: hostname,
|
|
68
79
|
path: path,
|
|
69
80
|
port: port,
|
|
70
|
-
method: method
|
|
81
|
+
method: method,
|
|
82
|
+
transport: transportAPI
|
|
71
83
|
};
|
|
72
84
|
}
|
|
73
85
|
|
package/src/browser/telemetry.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var _ = require('../utility');
|
|
2
|
+
var headers = require('../utility/headers');
|
|
2
3
|
var scrub = require('../scrub');
|
|
3
4
|
var urlparser = require('./url');
|
|
4
5
|
var domUtil = require('./domUtility');
|
|
@@ -362,7 +363,7 @@ Instrumenter.prototype.instrumentNetwork = function() {
|
|
|
362
363
|
if (args[1] && args[1].headers) {
|
|
363
364
|
// Argument may be a Headers object, or plain object. Ensure here that
|
|
364
365
|
// we are working with a Headers object with case-insensitive keys.
|
|
365
|
-
var reqHeaders =
|
|
366
|
+
var reqHeaders = headers(args[1].headers);
|
|
366
367
|
|
|
367
368
|
metadata.request_content_type = reqHeaders.get('Content-Type');
|
|
368
369
|
|
|
@@ -382,6 +383,9 @@ Instrumenter.prototype.instrumentNetwork = function() {
|
|
|
382
383
|
if (self.trackHttpErrors()) {
|
|
383
384
|
metadata.stack = (new Error()).stack;
|
|
384
385
|
}
|
|
386
|
+
|
|
387
|
+
// Start our handler before returning the promise. This allows resp.clone()
|
|
388
|
+
// to execute before other handlers touch the response.
|
|
385
389
|
return orig.apply(this, args).then(function (resp) {
|
|
386
390
|
metadata.end_time_ms = _.now();
|
|
387
391
|
metadata.status_code = resp.status;
|
|
@@ -394,6 +398,7 @@ Instrumenter.prototype.instrumentNetwork = function() {
|
|
|
394
398
|
if (self.autoInstrument.networkResponseBody) {
|
|
395
399
|
if (typeof resp.text === 'function') { // Response.text() is not implemented on some platforms
|
|
396
400
|
// The response must be cloned to prevent reading (and locking) the original stream.
|
|
401
|
+
// This must be done before other handlers touch the response.
|
|
397
402
|
body = resp.clone().text(); //returns a Promise
|
|
398
403
|
}
|
|
399
404
|
}
|
|
@@ -79,20 +79,25 @@ function addBaseInfo(item, options, callback) {
|
|
|
79
79
|
|
|
80
80
|
function addRequestInfo(window) {
|
|
81
81
|
return function(item, options, callback) {
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
var requestInfo = {};
|
|
83
|
+
|
|
84
|
+
if (window && window.location) {
|
|
85
|
+
requestInfo.url = window.location.href;
|
|
86
|
+
requestInfo.query_string = window.location.search;
|
|
84
87
|
}
|
|
88
|
+
|
|
85
89
|
var remoteString = '$remote_ip';
|
|
86
90
|
if (!options.captureIp) {
|
|
87
91
|
remoteString = null;
|
|
88
92
|
} else if (options.captureIp !== true) {
|
|
89
93
|
remoteString += '_anonymize';
|
|
90
94
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
95
|
+
if (remoteString) requestInfo.user_ip = remoteString;
|
|
96
|
+
|
|
97
|
+
if (Object.keys(requestInfo).length > 0) {
|
|
98
|
+
_.set(item, 'data.request', requestInfo);
|
|
99
|
+
}
|
|
100
|
+
|
|
96
101
|
callback(null, item);
|
|
97
102
|
};
|
|
98
103
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
var logger = require('../logger');
|
|
2
|
+
var _ = require('../../utility');
|
|
3
|
+
|
|
4
|
+
function makeFetchRequest(accessToken, url, method, data, callback, timeout) {
|
|
5
|
+
var controller;
|
|
6
|
+
var timeoutId;
|
|
7
|
+
|
|
8
|
+
if(_.isFiniteNumber(timeout)) {
|
|
9
|
+
controller = new AbortController();
|
|
10
|
+
timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
fetch(url, {
|
|
14
|
+
method: method,
|
|
15
|
+
headers: {
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
'X-Rollbar-Access-Token': accessToken,
|
|
18
|
+
signal: controller && controller.signal
|
|
19
|
+
},
|
|
20
|
+
body: data,
|
|
21
|
+
})
|
|
22
|
+
.then((response) => {
|
|
23
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
24
|
+
return response.json();
|
|
25
|
+
})
|
|
26
|
+
.then((data) => {
|
|
27
|
+
callback(null, data);
|
|
28
|
+
})
|
|
29
|
+
.catch((error) => {
|
|
30
|
+
logger.error(error.message);
|
|
31
|
+
callback(error);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = makeFetchRequest;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/*global XDomainRequest*/
|
|
2
|
+
|
|
3
|
+
var _ = require('../../utility');
|
|
4
|
+
var logger = require('../logger');
|
|
5
|
+
|
|
6
|
+
function makeXhrRequest(accessToken, url, method, data, callback, requestFactory, timeout) {
|
|
7
|
+
var request;
|
|
8
|
+
if (requestFactory) {
|
|
9
|
+
request = requestFactory();
|
|
10
|
+
} else {
|
|
11
|
+
request = _createXMLHTTPObject();
|
|
12
|
+
}
|
|
13
|
+
if (!request) {
|
|
14
|
+
// Give up, no way to send requests
|
|
15
|
+
return callback(new Error('No way to send a request'));
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
try {
|
|
19
|
+
var onreadystatechange = function() {
|
|
20
|
+
try {
|
|
21
|
+
if (onreadystatechange && request.readyState === 4) {
|
|
22
|
+
onreadystatechange = undefined;
|
|
23
|
+
|
|
24
|
+
var parseResponse = _.jsonParse(request.responseText);
|
|
25
|
+
if (_isSuccess(request)) {
|
|
26
|
+
callback(parseResponse.error, parseResponse.value);
|
|
27
|
+
return;
|
|
28
|
+
} else if (_isNormalFailure(request)) {
|
|
29
|
+
if (request.status === 403) {
|
|
30
|
+
// likely caused by using a server access token
|
|
31
|
+
var message = parseResponse.value && parseResponse.value.message;
|
|
32
|
+
logger.error(message);
|
|
33
|
+
}
|
|
34
|
+
// return valid http status codes
|
|
35
|
+
callback(new Error(String(request.status)));
|
|
36
|
+
} else {
|
|
37
|
+
// IE will return a status 12000+ on some sort of connection failure,
|
|
38
|
+
// so we return a blank error
|
|
39
|
+
// http://msdn.microsoft.com/en-us/library/aa383770%28VS.85%29.aspx
|
|
40
|
+
var msg = 'XHR response had no status code (likely connection failure)';
|
|
41
|
+
callback(_newRetriableError(msg));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch (ex) {
|
|
45
|
+
//jquery source mentions firefox may error out while accessing the
|
|
46
|
+
//request members if there is a network error
|
|
47
|
+
//https://github.com/jquery/jquery/blob/a938d7b1282fc0e5c52502c225ae8f0cef219f0a/src/ajax/xhr.js#L111
|
|
48
|
+
var exc;
|
|
49
|
+
if (ex && ex.stack) {
|
|
50
|
+
exc = ex;
|
|
51
|
+
} else {
|
|
52
|
+
exc = new Error(ex);
|
|
53
|
+
}
|
|
54
|
+
callback(exc);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
request.open(method, url, true);
|
|
59
|
+
if (request.setRequestHeader) {
|
|
60
|
+
request.setRequestHeader('Content-Type', 'application/json');
|
|
61
|
+
request.setRequestHeader('X-Rollbar-Access-Token', accessToken);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if(_.isFiniteNumber(timeout)) {
|
|
65
|
+
request.timeout = timeout;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
request.onreadystatechange = onreadystatechange;
|
|
69
|
+
request.send(data);
|
|
70
|
+
} catch (e1) {
|
|
71
|
+
// Sending using the normal xmlhttprequest object didn't work, try XDomainRequest
|
|
72
|
+
if (typeof XDomainRequest !== 'undefined') {
|
|
73
|
+
|
|
74
|
+
// Assume we are in a really old browser which has a bunch of limitations:
|
|
75
|
+
// http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
|
|
76
|
+
|
|
77
|
+
// Extreme paranoia: if we have XDomainRequest then we have a window, but just in case
|
|
78
|
+
if (!window || !window.location) {
|
|
79
|
+
return callback(new Error('No window available during request, unknown environment'));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// If the current page is http, try and send over http
|
|
83
|
+
if (window.location.href.substring(0, 5) === 'http:' && url.substring(0, 5) === 'https') {
|
|
84
|
+
url = 'http' + url.substring(5);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
var xdomainrequest = new XDomainRequest();
|
|
88
|
+
xdomainrequest.onprogress = function() {};
|
|
89
|
+
xdomainrequest.ontimeout = function() {
|
|
90
|
+
var msg = 'Request timed out';
|
|
91
|
+
var code = 'ETIMEDOUT';
|
|
92
|
+
callback(_newRetriableError(msg, code));
|
|
93
|
+
};
|
|
94
|
+
xdomainrequest.onerror = function() {
|
|
95
|
+
callback(new Error('Error during request'));
|
|
96
|
+
};
|
|
97
|
+
xdomainrequest.onload = function() {
|
|
98
|
+
var parseResponse = _.jsonParse(xdomainrequest.responseText);
|
|
99
|
+
callback(parseResponse.error, parseResponse.value);
|
|
100
|
+
};
|
|
101
|
+
xdomainrequest.open(method, url, true);
|
|
102
|
+
xdomainrequest.send(data);
|
|
103
|
+
} else {
|
|
104
|
+
callback(new Error('Cannot find a method to transport a request'));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} catch (e2) {
|
|
108
|
+
callback(e2);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function _createXMLHTTPObject() {
|
|
113
|
+
/* global ActiveXObject:false */
|
|
114
|
+
|
|
115
|
+
var factories = [
|
|
116
|
+
function () {
|
|
117
|
+
return new XMLHttpRequest();
|
|
118
|
+
},
|
|
119
|
+
function () {
|
|
120
|
+
return new ActiveXObject('Msxml2.XMLHTTP');
|
|
121
|
+
},
|
|
122
|
+
function () {
|
|
123
|
+
return new ActiveXObject('Msxml3.XMLHTTP');
|
|
124
|
+
},
|
|
125
|
+
function () {
|
|
126
|
+
return new ActiveXObject('Microsoft.XMLHTTP');
|
|
127
|
+
}
|
|
128
|
+
];
|
|
129
|
+
var xmlhttp;
|
|
130
|
+
var i;
|
|
131
|
+
var numFactories = factories.length;
|
|
132
|
+
for (i = 0; i < numFactories; i++) {
|
|
133
|
+
/* eslint-disable no-empty */
|
|
134
|
+
try {
|
|
135
|
+
xmlhttp = factories[i]();
|
|
136
|
+
break;
|
|
137
|
+
} catch (e) {
|
|
138
|
+
// pass
|
|
139
|
+
}
|
|
140
|
+
/* eslint-enable no-empty */
|
|
141
|
+
}
|
|
142
|
+
return xmlhttp;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function _isSuccess(r) {
|
|
146
|
+
return r && r.status && r.status === 200;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function _isNormalFailure(r) {
|
|
150
|
+
return r && _.isType(r.status, 'number') && r.status >= 400 && r.status < 600;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function _newRetriableError(message, code) {
|
|
154
|
+
var err = new Error(message);
|
|
155
|
+
err.code = code || 'ENOTFOUND';
|
|
156
|
+
return err;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
module.exports = makeXhrRequest;
|
package/src/browser/transport.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
/*global XDomainRequest*/
|
|
2
|
-
|
|
3
1
|
var _ = require('../utility');
|
|
4
|
-
var
|
|
2
|
+
var makeFetchRequest = require('./transport/fetch');
|
|
3
|
+
var makeXhrRequest = require('./transport/xhr');
|
|
5
4
|
|
|
6
5
|
/*
|
|
7
6
|
* accessToken may be embedded in payload but that should not
|
|
@@ -13,6 +12,7 @@ var logger = require('./logger');
|
|
|
13
12
|
* path
|
|
14
13
|
* port
|
|
15
14
|
* method
|
|
15
|
+
* transport ('xhr' | 'fetch')
|
|
16
16
|
* }
|
|
17
17
|
*
|
|
18
18
|
* params is an object containing key/value pairs. These
|
|
@@ -32,7 +32,9 @@ Transport.prototype.get = function(accessToken, options, params, callback, reque
|
|
|
32
32
|
|
|
33
33
|
var method = 'GET';
|
|
34
34
|
var url = _.formatUrl(options);
|
|
35
|
-
_makeZoneRequest(
|
|
35
|
+
this._makeZoneRequest(
|
|
36
|
+
accessToken, url, method, null, callback, requestFactory, options.timeout, options.transport
|
|
37
|
+
);
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
Transport.prototype.post = function(accessToken, options, payload, callback, requestFactory) {
|
|
@@ -57,7 +59,9 @@ Transport.prototype.post = function(accessToken, options, payload, callback, req
|
|
|
57
59
|
var writeData = stringifyResult.value;
|
|
58
60
|
var method = 'POST';
|
|
59
61
|
var url = _.formatUrl(options);
|
|
60
|
-
_makeZoneRequest(
|
|
62
|
+
this._makeZoneRequest(
|
|
63
|
+
accessToken, url, method, writeData, callback, requestFactory, options.timeout, options.transport
|
|
64
|
+
);
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
Transport.prototype.postJsonPayload = function (accessToken, options, jsonPayload, callback, requestFactory) {
|
|
@@ -67,7 +71,9 @@ Transport.prototype.postJsonPayload = function (accessToken, options, jsonPayloa
|
|
|
67
71
|
|
|
68
72
|
var method = 'POST';
|
|
69
73
|
var url = _.formatUrl(options);
|
|
70
|
-
_makeZoneRequest(
|
|
74
|
+
this._makeZoneRequest(
|
|
75
|
+
accessToken, url, method, jsonPayload, callback, requestFactory, options.timeout, options.transport
|
|
76
|
+
);
|
|
71
77
|
}
|
|
72
78
|
|
|
73
79
|
|
|
@@ -75,7 +81,7 @@ Transport.prototype.postJsonPayload = function (accessToken, options, jsonPayloa
|
|
|
75
81
|
// so Angular change detection isn't triggered on each API call.
|
|
76
82
|
// This is the equivalent of runOutsideAngular().
|
|
77
83
|
//
|
|
78
|
-
function
|
|
84
|
+
Transport.prototype._makeZoneRequest = function () {
|
|
79
85
|
var gWindow = ((typeof window != 'undefined') && window) || ((typeof self != 'undefined') && self);
|
|
80
86
|
var currentZone = gWindow && gWindow.Zone && gWindow.Zone.current;
|
|
81
87
|
var args = Array.prototype.slice.call(arguments);
|
|
@@ -83,10 +89,24 @@ function _makeZoneRequest() {
|
|
|
83
89
|
if (currentZone && currentZone._name === 'angular') {
|
|
84
90
|
var rootZone = currentZone._parent;
|
|
85
91
|
rootZone.run(function () {
|
|
86
|
-
_makeRequest.apply(undefined, args);
|
|
92
|
+
this._makeRequest.apply(undefined, args);
|
|
87
93
|
});
|
|
88
94
|
} else {
|
|
89
|
-
_makeRequest.apply(undefined, args);
|
|
95
|
+
this._makeRequest.apply(undefined, args);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Transport.prototype._makeRequest = function (
|
|
100
|
+
accessToken, url, method, data, callback, requestFactory, timeout, transport
|
|
101
|
+
) {
|
|
102
|
+
if (typeof RollbarProxy !== 'undefined') {
|
|
103
|
+
return _proxyRequest(data, callback);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (transport === 'fetch') {
|
|
107
|
+
makeFetchRequest(accessToken, url, method, data, callback, timeout)
|
|
108
|
+
} else {
|
|
109
|
+
makeXhrRequest(accessToken, url, method, data, callback, requestFactory, timeout)
|
|
90
110
|
}
|
|
91
111
|
}
|
|
92
112
|
|
|
@@ -102,161 +122,4 @@ function _proxyRequest(json, callback) {
|
|
|
102
122
|
);
|
|
103
123
|
}
|
|
104
124
|
|
|
105
|
-
function _makeRequest(accessToken, url, method, data, callback, requestFactory, timeout) {
|
|
106
|
-
if (typeof RollbarProxy !== 'undefined') {
|
|
107
|
-
return _proxyRequest(data, callback);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
var request;
|
|
111
|
-
if (requestFactory) {
|
|
112
|
-
request = requestFactory();
|
|
113
|
-
} else {
|
|
114
|
-
request = _createXMLHTTPObject();
|
|
115
|
-
}
|
|
116
|
-
if (!request) {
|
|
117
|
-
// Give up, no way to send requests
|
|
118
|
-
return callback(new Error('No way to send a request'));
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
try {
|
|
122
|
-
var onreadystatechange = function() {
|
|
123
|
-
try {
|
|
124
|
-
if (onreadystatechange && request.readyState === 4) {
|
|
125
|
-
onreadystatechange = undefined;
|
|
126
|
-
|
|
127
|
-
var parseResponse = _.jsonParse(request.responseText);
|
|
128
|
-
if (_isSuccess(request)) {
|
|
129
|
-
callback(parseResponse.error, parseResponse.value);
|
|
130
|
-
return;
|
|
131
|
-
} else if (_isNormalFailure(request)) {
|
|
132
|
-
if (request.status === 403) {
|
|
133
|
-
// likely caused by using a server access token
|
|
134
|
-
var message = parseResponse.value && parseResponse.value.message;
|
|
135
|
-
logger.error(message);
|
|
136
|
-
}
|
|
137
|
-
// return valid http status codes
|
|
138
|
-
callback(new Error(String(request.status)));
|
|
139
|
-
} else {
|
|
140
|
-
// IE will return a status 12000+ on some sort of connection failure,
|
|
141
|
-
// so we return a blank error
|
|
142
|
-
// http://msdn.microsoft.com/en-us/library/aa383770%28VS.85%29.aspx
|
|
143
|
-
var msg = 'XHR response had no status code (likely connection failure)';
|
|
144
|
-
callback(_newRetriableError(msg));
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
} catch (ex) {
|
|
148
|
-
//jquery source mentions firefox may error out while accessing the
|
|
149
|
-
//request members if there is a network error
|
|
150
|
-
//https://github.com/jquery/jquery/blob/a938d7b1282fc0e5c52502c225ae8f0cef219f0a/src/ajax/xhr.js#L111
|
|
151
|
-
var exc;
|
|
152
|
-
if (ex && ex.stack) {
|
|
153
|
-
exc = ex;
|
|
154
|
-
} else {
|
|
155
|
-
exc = new Error(ex);
|
|
156
|
-
}
|
|
157
|
-
callback(exc);
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
request.open(method, url, true);
|
|
162
|
-
if (request.setRequestHeader) {
|
|
163
|
-
request.setRequestHeader('Content-Type', 'application/json');
|
|
164
|
-
request.setRequestHeader('X-Rollbar-Access-Token', accessToken);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if(_.isFiniteNumber(timeout)) {
|
|
168
|
-
request.timeout = timeout;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
request.onreadystatechange = onreadystatechange;
|
|
172
|
-
request.send(data);
|
|
173
|
-
} catch (e1) {
|
|
174
|
-
// Sending using the normal xmlhttprequest object didn't work, try XDomainRequest
|
|
175
|
-
if (typeof XDomainRequest !== 'undefined') {
|
|
176
|
-
|
|
177
|
-
// Assume we are in a really old browser which has a bunch of limitations:
|
|
178
|
-
// http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
|
|
179
|
-
|
|
180
|
-
// Extreme paranoia: if we have XDomainRequest then we have a window, but just in case
|
|
181
|
-
if (!window || !window.location) {
|
|
182
|
-
return callback(new Error('No window available during request, unknown environment'));
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// If the current page is http, try and send over http
|
|
186
|
-
if (window.location.href.substring(0, 5) === 'http:' && url.substring(0, 5) === 'https') {
|
|
187
|
-
url = 'http' + url.substring(5);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
var xdomainrequest = new XDomainRequest();
|
|
191
|
-
xdomainrequest.onprogress = function() {};
|
|
192
|
-
xdomainrequest.ontimeout = function() {
|
|
193
|
-
var msg = 'Request timed out';
|
|
194
|
-
var code = 'ETIMEDOUT';
|
|
195
|
-
callback(_newRetriableError(msg, code));
|
|
196
|
-
};
|
|
197
|
-
xdomainrequest.onerror = function() {
|
|
198
|
-
callback(new Error('Error during request'));
|
|
199
|
-
};
|
|
200
|
-
xdomainrequest.onload = function() {
|
|
201
|
-
var parseResponse = _.jsonParse(xdomainrequest.responseText);
|
|
202
|
-
callback(parseResponse.error, parseResponse.value);
|
|
203
|
-
};
|
|
204
|
-
xdomainrequest.open(method, url, true);
|
|
205
|
-
xdomainrequest.send(data);
|
|
206
|
-
} else {
|
|
207
|
-
callback(new Error('Cannot find a method to transport a request'));
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
} catch (e2) {
|
|
211
|
-
callback(e2);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function _createXMLHTTPObject() {
|
|
216
|
-
/* global ActiveXObject:false */
|
|
217
|
-
|
|
218
|
-
var factories = [
|
|
219
|
-
function () {
|
|
220
|
-
return new XMLHttpRequest();
|
|
221
|
-
},
|
|
222
|
-
function () {
|
|
223
|
-
return new ActiveXObject('Msxml2.XMLHTTP');
|
|
224
|
-
},
|
|
225
|
-
function () {
|
|
226
|
-
return new ActiveXObject('Msxml3.XMLHTTP');
|
|
227
|
-
},
|
|
228
|
-
function () {
|
|
229
|
-
return new ActiveXObject('Microsoft.XMLHTTP');
|
|
230
|
-
}
|
|
231
|
-
];
|
|
232
|
-
var xmlhttp;
|
|
233
|
-
var i;
|
|
234
|
-
var numFactories = factories.length;
|
|
235
|
-
for (i = 0; i < numFactories; i++) {
|
|
236
|
-
/* eslint-disable no-empty */
|
|
237
|
-
try {
|
|
238
|
-
xmlhttp = factories[i]();
|
|
239
|
-
break;
|
|
240
|
-
} catch (e) {
|
|
241
|
-
// pass
|
|
242
|
-
}
|
|
243
|
-
/* eslint-enable no-empty */
|
|
244
|
-
}
|
|
245
|
-
return xmlhttp;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
function _isSuccess(r) {
|
|
249
|
-
return r && r.status && r.status === 200;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function _isNormalFailure(r) {
|
|
253
|
-
return r && _.isType(r.status, 'number') && r.status >= 400 && r.status < 600;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function _newRetriableError(message, code) {
|
|
257
|
-
var err = new Error(message);
|
|
258
|
-
err.code = code || 'ENOTFOUND';
|
|
259
|
-
return err;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
125
|
module.exports = Transport;
|
package/src/defaults.js
CHANGED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* headers - Detect when fetch Headers are undefined and use a partial polyfill.
|
|
3
|
+
*
|
|
4
|
+
* A full polyfill is not used in order to keep package size as small as possible.
|
|
5
|
+
* Since this is only used internally and is not added to the window object,
|
|
6
|
+
* the full interface doesn't need to be supported.
|
|
7
|
+
*
|
|
8
|
+
* This implementation is modified from whatwg-fetch:
|
|
9
|
+
* https://github.com/github/fetch
|
|
10
|
+
*/
|
|
11
|
+
function headers(headers) {
|
|
12
|
+
if (typeof Headers === 'undefined') {
|
|
13
|
+
return new FetchHeaders(headers);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return new Headers(headers);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function normalizeName(name) {
|
|
20
|
+
if (typeof name !== 'string') {
|
|
21
|
+
name = String(name)
|
|
22
|
+
}
|
|
23
|
+
return name.toLowerCase()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeValue(value) {
|
|
27
|
+
if (typeof value !== 'string') {
|
|
28
|
+
value = String(value)
|
|
29
|
+
}
|
|
30
|
+
return value
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function iteratorFor(items) {
|
|
34
|
+
var iterator = {
|
|
35
|
+
next: function() {
|
|
36
|
+
var value = items.shift()
|
|
37
|
+
return {done: value === undefined, value: value}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return iterator
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function FetchHeaders(headers) {
|
|
45
|
+
this.map = {}
|
|
46
|
+
|
|
47
|
+
if (headers instanceof FetchHeaders) {
|
|
48
|
+
headers.forEach(function(value, name) {
|
|
49
|
+
this.append(name, value)
|
|
50
|
+
}, this)
|
|
51
|
+
} else if (Array.isArray(headers)) {
|
|
52
|
+
headers.forEach(function(header) {
|
|
53
|
+
this.append(header[0], header[1])
|
|
54
|
+
}, this)
|
|
55
|
+
} else if (headers) {
|
|
56
|
+
Object.getOwnPropertyNames(headers).forEach(function(name) {
|
|
57
|
+
this.append(name, headers[name])
|
|
58
|
+
}, this)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
FetchHeaders.prototype.append = function(name, value) {
|
|
63
|
+
name = normalizeName(name)
|
|
64
|
+
value = normalizeValue(value)
|
|
65
|
+
var oldValue = this.map[name]
|
|
66
|
+
this.map[name] = oldValue ? oldValue + ', ' + value : value
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
FetchHeaders.prototype.get = function(name) {
|
|
70
|
+
name = normalizeName(name)
|
|
71
|
+
return this.has(name) ? this.map[name] : null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
FetchHeaders.prototype.has = function(name) {
|
|
75
|
+
return this.map.hasOwnProperty(normalizeName(name))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
FetchHeaders.prototype.forEach = function(callback, thisArg) {
|
|
79
|
+
for (var name in this.map) {
|
|
80
|
+
if (this.map.hasOwnProperty(name)) {
|
|
81
|
+
callback.call(thisArg, this.map[name], name, this)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
FetchHeaders.prototype.entries = function() {
|
|
87
|
+
var items = []
|
|
88
|
+
this.forEach(function(value, name) {
|
|
89
|
+
items.push([name, value])
|
|
90
|
+
})
|
|
91
|
+
return iteratorFor(items)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = headers;
|