rollbar 2.25.1 → 2.25.2
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 +127 -18
- 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 +127 -18
- 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 +127 -18
- 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 +127 -18
- 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/package.json +1 -1
- package/src/browser/telemetry.js +2 -1
- package/src/browser/transforms.js +12 -7
- package/src/defaults.js +1 -1
- package/src/utility/headers.js +94 -0
- package/test/browser.rollbar.test.js +86 -8
- package/test/browser.transforms.test.js +15 -1
package/package.json
CHANGED
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
|
|
|
@@ -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
|
}
|
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;
|
|
@@ -1495,17 +1495,21 @@ describe('options.autoInstrument', function() {
|
|
|
1495
1495
|
if(xhr.readyState === 4) {
|
|
1496
1496
|
try {
|
|
1497
1497
|
setTimeout(function() {
|
|
1498
|
-
|
|
1498
|
+
try {
|
|
1499
|
+
server.respond();
|
|
1499
1500
|
|
|
1500
|
-
|
|
1501
|
-
|
|
1501
|
+
expect(server.requests.length).to.eql(2);
|
|
1502
|
+
var body = JSON.parse(server.requests[1].requestBody);
|
|
1502
1503
|
|
|
1503
|
-
|
|
1504
|
+
expect(body.data.body.trace.exception.message).to.eql('HTTP request failed with Status 404');
|
|
1504
1505
|
|
|
1505
|
-
|
|
1506
|
-
|
|
1506
|
+
// Just knowing a stack is present is enough for this test.
|
|
1507
|
+
expect(body.data.body.trace.frames.length).to.be.above(1);
|
|
1507
1508
|
|
|
1508
|
-
|
|
1509
|
+
done();
|
|
1510
|
+
} catch (e) {
|
|
1511
|
+
done(e);
|
|
1512
|
+
}
|
|
1509
1513
|
}, 1);
|
|
1510
1514
|
} catch (e) {
|
|
1511
1515
|
done(e);
|
|
@@ -1606,7 +1610,7 @@ describe('options.autoInstrument', function() {
|
|
|
1606
1610
|
})
|
|
1607
1611
|
});
|
|
1608
1612
|
|
|
1609
|
-
it('should
|
|
1613
|
+
it('should report error for http 4xx fetch calls, when enabled', function(done) {
|
|
1610
1614
|
var server = window.server;
|
|
1611
1615
|
stubResponse(server);
|
|
1612
1616
|
server.requests.length = 0;
|
|
@@ -1659,6 +1663,80 @@ describe('options.autoInstrument', function() {
|
|
|
1659
1663
|
})
|
|
1660
1664
|
});
|
|
1661
1665
|
|
|
1666
|
+
it('should add telemetry headers when fetch Headers object is undefined', function(done) {
|
|
1667
|
+
var server = window.server;
|
|
1668
|
+
stubResponse(server);
|
|
1669
|
+
server.requests.length = 0;
|
|
1670
|
+
|
|
1671
|
+
window.fetchStub = sinon.stub(window, 'fetch');
|
|
1672
|
+
|
|
1673
|
+
var readableStream = new ReadableStream({
|
|
1674
|
+
start(controller) {
|
|
1675
|
+
controller.enqueue(JSON.stringify({name: 'foo', password: '123456'}));
|
|
1676
|
+
controller.close();
|
|
1677
|
+
}
|
|
1678
|
+
});
|
|
1679
|
+
|
|
1680
|
+
window.fetch.returns(Promise.resolve(new Response(
|
|
1681
|
+
readableStream,
|
|
1682
|
+
{ status: 200, statusText: 'OK', headers: { 'content-type': 'application/json', 'password': '123456' }}
|
|
1683
|
+
)));
|
|
1684
|
+
|
|
1685
|
+
var options = {
|
|
1686
|
+
accessToken: 'POST_CLIENT_ITEM_TOKEN',
|
|
1687
|
+
autoInstrument: {
|
|
1688
|
+
log: false,
|
|
1689
|
+
network: true,
|
|
1690
|
+
networkResponseHeaders: true,
|
|
1691
|
+
networkRequestHeaders: true
|
|
1692
|
+
}
|
|
1693
|
+
};
|
|
1694
|
+
var rollbar = window.rollbar = new Rollbar(options);
|
|
1695
|
+
|
|
1696
|
+
// Remove Headers from window object
|
|
1697
|
+
var originalHeaders = window.Headers;
|
|
1698
|
+
delete window.Headers;
|
|
1699
|
+
|
|
1700
|
+
const fetchInit = {
|
|
1701
|
+
method: 'POST',
|
|
1702
|
+
headers: {'Content-Type': 'application/json', Secret: '123456'},
|
|
1703
|
+
body: JSON.stringify({name: 'bar', secret: 'xhr post'})
|
|
1704
|
+
};
|
|
1705
|
+
var fetchRequest = new Request('https://example.com/xhr-test');
|
|
1706
|
+
window.fetch(fetchRequest, fetchInit)
|
|
1707
|
+
.then(function(response) {
|
|
1708
|
+
try {
|
|
1709
|
+
rollbar.log('test'); // generate a payload to inspect
|
|
1710
|
+
setTimeout(function() {
|
|
1711
|
+
try {
|
|
1712
|
+
server.respond();
|
|
1713
|
+
|
|
1714
|
+
expect(server.requests.length).to.eql(1);
|
|
1715
|
+
var body = JSON.parse(server.requests[0].requestBody);
|
|
1716
|
+
|
|
1717
|
+
// Verify request headers capture and case-insensitive scrubbing
|
|
1718
|
+
expect(body.data.body.telemetry[0].body.request_headers).to.eql({'content-type': 'application/json', secret: '********'});
|
|
1719
|
+
|
|
1720
|
+
// Verify response headers capture and case-insensitive scrubbing
|
|
1721
|
+
expect(body.data.body.telemetry[0].body.response.headers).to.eql({'content-type': 'application/json', password: '********'});
|
|
1722
|
+
|
|
1723
|
+
// Assert that the original stream reader hasn't been read.
|
|
1724
|
+
expect(response.bodyUsed).to.eql(false);
|
|
1725
|
+
|
|
1726
|
+
rollbar.configure({ autoInstrument: false });
|
|
1727
|
+
window.fetch.restore();
|
|
1728
|
+
window.Headers = originalHeaders;
|
|
1729
|
+
done();
|
|
1730
|
+
} catch (e) {
|
|
1731
|
+
done(e);
|
|
1732
|
+
}
|
|
1733
|
+
});
|
|
1734
|
+
} catch (e) {
|
|
1735
|
+
done(e);
|
|
1736
|
+
}
|
|
1737
|
+
})
|
|
1738
|
+
});
|
|
1739
|
+
|
|
1662
1740
|
it('should add a diagnostic message when wrapConsole fails', function(done) {
|
|
1663
1741
|
var server = window.server;
|
|
1664
1742
|
stubResponse(server);
|
|
@@ -226,9 +226,10 @@ describe('addRequestInfo', function() {
|
|
|
226
226
|
it('should use window info to set request properties', function(done) {
|
|
227
227
|
var args = ['a message'];
|
|
228
228
|
var item = itemFromArgs(args);
|
|
229
|
-
var options = {};
|
|
229
|
+
var options = { captureIp: 'anonymize' };
|
|
230
230
|
t.addRequestInfo(window)(item, options, function(e, i) {
|
|
231
231
|
expect(i.data.request).to.be.ok();
|
|
232
|
+
expect(i.data.request.user_ip).to.eql('$remote_ip_anonymize');
|
|
232
233
|
done(e);
|
|
233
234
|
});
|
|
234
235
|
});
|
|
@@ -243,6 +244,19 @@ describe('addRequestInfo', function() {
|
|
|
243
244
|
done(e);
|
|
244
245
|
});
|
|
245
246
|
});
|
|
247
|
+
it('should honor captureIp without window', function(done) {
|
|
248
|
+
var args = ['a message'];
|
|
249
|
+
var item = itemFromArgs(args);
|
|
250
|
+
item.data = {};
|
|
251
|
+
var options = { captureIp: true };
|
|
252
|
+
var w = null;
|
|
253
|
+
t.addRequestInfo(w)(item, options, function(e, i) {
|
|
254
|
+
expect(i.data.request.url).to.not.be.ok();
|
|
255
|
+
expect(i.data.request.query_string).to.not.be.ok();
|
|
256
|
+
expect(i.data.request.user_ip).to.eql('$remote_ip');
|
|
257
|
+
done(e);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
246
260
|
});
|
|
247
261
|
|
|
248
262
|
describe('addClientInfo', function() {
|