Browse Source

fix(loader): Avoid setting/resetting `window.onerror` (#47311)

This uses `addEventListener` instead of `window.onerror` to set the
handler for the loader.
This way, we avoid infinite recursion when users also do that, e.g.
right after loading the loader:

```js
const oldOnError = window.onerror;

window.onerror = function () {
  console.log('custom error');
  oldOnError && oldOnError.apply(this, arguments);
};

window.doSomethingWrong();
```
Francesco Novy 1 year ago
parent
commit
2a852b76fc

+ 19 - 36
src/sentry/templates/sentry/js-sdk-loader.js.tmpl

@@ -32,6 +32,21 @@
         queue.data.push(content);
     };
     queue.data = [];
+    function onError() {
+        // Use keys as "data type" to save some characters"
+        queue({
+            e: [].slice.call(arguments),
+        });
+    }
+    function onUnhandledRejection(e) {
+        queue({
+            p: 'reason' in e
+                ? e.reason
+                : 'detail' in e && 'reason' in e.detail
+                    ? e.detail.reason
+                    : e,
+        });
+    }
     function injectSdk(callbacks) {
         if (injected) {
             return;
@@ -50,14 +65,8 @@
         // Once our SDK is loaded
         _newScriptTag.addEventListener('load', function () {
             try {
-                // Restore onerror/onunhandledrejection handlers - only if not mutated in the meanwhile
-                if (_window[_onerror] && _window[_onerror].__SENTRY_LOADER__) {
-                    _window[_onerror] = _oldOnerror;
-                }
-                if (_window[_onunhandledrejection] &&
-                    _window[_onunhandledrejection].__SENTRY_LOADER__) {
-                    _window[_onunhandledrejection] = _oldOnunhandledrejection;
-                }
+                _window.removeEventListener('error', onError);
+                _window.removeEventListener('unhandledrejection', onUnhandledRejection);
                 // Add loader as SDK source
                 _window.SENTRY_SDK_SOURCE = 'loader';
                 var SDK_1 = _window[_namespace];
@@ -186,34 +195,8 @@
             queue({ f: f, a: arguments });
         };
     });
-    // Store reference to the old `onerror` handler and override it with our own function
-    // that will just push exceptions to the queue and call through old handler if we found one
-    var _oldOnerror = _window[_onerror];
-    _window[_onerror] = function () {
-        // Use keys as "data type" to save some characters"
-        queue({
-            e: [].slice.call(arguments),
-        });
-        if (_oldOnerror) {
-            _oldOnerror.apply(_window, arguments);
-        }
-    };
-    _window[_onerror].__SENTRY_LOADER__ = true;
-    // Do the same store/queue/call operations for `onunhandledrejection` event
-    var _oldOnunhandledrejection = _window[_onunhandledrejection];
-    _window[_onunhandledrejection] = function (e) {
-        queue({
-            p: 'reason' in e
-                ? e.reason
-                : 'detail' in e && 'reason' in e.detail
-                    ? e.detail.reason
-                    : e,
-        });
-        if (_oldOnunhandledrejection) {
-            _oldOnunhandledrejection.apply(_window, arguments);
-        }
-    };
-    _window[_onunhandledrejection].__SENTRY_LOADER__ = true;
+    _window.addEventListener('error', onError);
+    _window.addEventListener('unhandledrejection', onUnhandledRejection);
     if (!lazy) {
         setTimeout(function () {
             injectSdk(onLoadCallbacks);

File diff suppressed because it is too large
+ 0 - 0
src/sentry/templates/sentry/js-sdk-loader.min.js.tmpl


+ 22 - 41
src/sentry/templates/sentry/js-sdk-loader.ts

@@ -54,6 +54,24 @@ declare const __LOADER__IS_LAZY__: any;
   };
   queue.data = [];
 
+  function onError() {
+    // Use keys as "data type" to save some characters"
+    queue({
+      e: [].slice.call(arguments),
+    });
+  }
+
+  function onUnhandledRejection(e) {
+    queue({
+      p:
+        'reason' in e
+          ? e.reason
+          : 'detail' in e && 'reason' in e.detail
+          ? e.detail.reason
+          : e,
+    });
+  }
+
   function injectSdk(callbacks) {
     if (injected) {
       return;
@@ -74,16 +92,8 @@ declare const __LOADER__IS_LAZY__: any;
     // Once our SDK is loaded
     _newScriptTag.addEventListener('load', function () {
       try {
-        // Restore onerror/onunhandledrejection handlers - only if not mutated in the meanwhile
-        if (_window[_onerror] && _window[_onerror].__SENTRY_LOADER__) {
-          _window[_onerror] = _oldOnerror;
-        }
-        if (
-          _window[_onunhandledrejection] &&
-          _window[_onunhandledrejection].__SENTRY_LOADER__
-        ) {
-          _window[_onunhandledrejection] = _oldOnunhandledrejection;
-        }
+        _window.removeEventListener('error', onError);
+        _window.removeEventListener('unhandledrejection', onUnhandledRejection);
 
         // Add loader as SDK source
         _window.SENTRY_SDK_SOURCE = 'loader';
@@ -239,37 +249,8 @@ declare const __LOADER__IS_LAZY__: any;
     };
   });
 
-  // Store reference to the old `onerror` handler and override it with our own function
-  // that will just push exceptions to the queue and call through old handler if we found one
-  const _oldOnerror = _window[_onerror];
-  _window[_onerror] = function () {
-    // Use keys as "data type" to save some characters"
-    queue({
-      e: [].slice.call(arguments),
-    });
-
-    if (_oldOnerror) {
-      _oldOnerror.apply(_window, arguments);
-    }
-  };
-  _window[_onerror].__SENTRY_LOADER__ = true;
-
-  // Do the same store/queue/call operations for `onunhandledrejection` event
-  const _oldOnunhandledrejection = _window[_onunhandledrejection];
-  _window[_onunhandledrejection] = function (e) {
-    queue({
-      p:
-        'reason' in e
-          ? e.reason
-          : 'detail' in e && 'reason' in e.detail
-          ? e.detail.reason
-          : e,
-    });
-    if (_oldOnunhandledrejection) {
-      _oldOnunhandledrejection.apply(_window, arguments);
-    }
-  };
-  _window[_onunhandledrejection].__SENTRY_LOADER__ = true;
+  _window.addEventListener('error', onError);
+  _window.addEventListener('unhandledrejection', onUnhandledRejection);
 
   if (!lazy) {
     setTimeout(function () {

Some files were not shown because too many files changed in this diff