UNPKG

4.01 kBJavaScriptView Raw
1Object.defineProperty(exports, "__esModule", { value: true });
2var utils_1 = require("@sentry/utils");
3var flags_1 = require("../flags");
4var global = utils_1.getGlobalObject();
5var cachedFetchImpl;
6/**
7 * A special usecase for incorrectly wrapped Fetch APIs in conjunction with ad-blockers.
8 * Whenever someone wraps the Fetch API and returns the wrong promise chain,
9 * this chain becomes orphaned and there is no possible way to capture it's rejections
10 * other than allowing it bubble up to this very handler. eg.
11 *
12 * const f = window.fetch;
13 * window.fetch = function () {
14 * const p = f.apply(this, arguments);
15 *
16 * p.then(function() {
17 * console.log('hi.');
18 * });
19 *
20 * return p;
21 * }
22 *
23 * `p.then(function () { ... })` is producing a completely separate promise chain,
24 * however, what's returned is `p` - the result of original `fetch` call.
25 *
26 * This mean, that whenever we use the Fetch API to send our own requests, _and_
27 * some ad-blocker blocks it, this orphaned chain will _always_ reject,
28 * effectively causing another event to be captured.
29 * This makes a whole process become an infinite loop, which we need to somehow
30 * deal with, and break it in one way or another.
31 *
32 * To deal with this issue, we are making sure that we _always_ use the real
33 * browser Fetch API, instead of relying on what `window.fetch` exposes.
34 * The only downside to this would be missing our own requests as breadcrumbs,
35 * but because we are already not doing this, it should be just fine.
36 *
37 * Possible failed fetch error messages per-browser:
38 *
39 * Chrome: Failed to fetch
40 * Edge: Failed to Fetch
41 * Firefox: NetworkError when attempting to fetch resource
42 * Safari: resource blocked by content blocker
43 */
44function getNativeFetchImplementation() {
45 if (cachedFetchImpl) {
46 return cachedFetchImpl;
47 }
48 /* eslint-disable @typescript-eslint/unbound-method */
49 // Fast path to avoid DOM I/O
50 if (utils_1.isNativeFetch(global.fetch)) {
51 return (cachedFetchImpl = global.fetch.bind(global));
52 }
53 var document = global.document;
54 var fetchImpl = global.fetch;
55 // eslint-disable-next-line deprecation/deprecation
56 if (document && typeof document.createElement === 'function') {
57 try {
58 var sandbox = document.createElement('iframe');
59 sandbox.hidden = true;
60 document.head.appendChild(sandbox);
61 var contentWindow = sandbox.contentWindow;
62 if (contentWindow && contentWindow.fetch) {
63 fetchImpl = contentWindow.fetch;
64 }
65 document.head.removeChild(sandbox);
66 }
67 catch (e) {
68 flags_1.IS_DEBUG_BUILD &&
69 utils_1.logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', e);
70 }
71 }
72 return (cachedFetchImpl = fetchImpl.bind(global));
73 /* eslint-enable @typescript-eslint/unbound-method */
74}
75exports.getNativeFetchImplementation = getNativeFetchImplementation;
76/**
77 * Sends sdk client report using sendBeacon or fetch as a fallback if available
78 *
79 * @param url report endpoint
80 * @param body report payload
81 */
82function sendReport(url, body) {
83 var isRealNavigator = Object.prototype.toString.call(global && global.navigator) === '[object Navigator]';
84 var hasSendBeacon = isRealNavigator && typeof global.navigator.sendBeacon === 'function';
85 if (hasSendBeacon) {
86 // Prevent illegal invocations - https://xgwang.me/posts/you-may-not-know-beacon/#it-may-throw-error%2C-be-sure-to-catch
87 var sendBeacon = global.navigator.sendBeacon.bind(global.navigator);
88 return sendBeacon(url, body);
89 }
90 if (utils_1.supportsFetch()) {
91 var fetch_1 = getNativeFetchImplementation();
92 return utils_1.forget(fetch_1(url, {
93 body: body,
94 method: 'POST',
95 credentials: 'omit',
96 keepalive: true,
97 }));
98 }
99}
100exports.sendReport = sendReport;
101//# sourceMappingURL=utils.js.map
\No newline at end of file