1 | Object.defineProperty(exports, "__esModule", { value: true });
|
2 | var utils_1 = require("@sentry/utils");
|
3 | var flags_1 = require("../flags");
|
4 | var global = utils_1.getGlobalObject();
|
5 | var 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 | */
|
44 | function 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 | }
|
75 | exports.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 | */
|
82 | function 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 | }
|
100 | exports.sendReport = sendReport;
|
101 | //# sourceMappingURL=utils.js.map |
\ | No newline at end of file |