-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
ref(core): Remove redundant iframe check in supportsNativeFetch
#19853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
93cfe54
8f83ce9
dde904b
f1ffa6f
f7c95ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,4 @@ | ||
| import { debug, isNativeFunction } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from './debug-build'; | ||
| import { getNativeImplementationFromIframe, isNativeFunction } from '@sentry/core'; | ||
| import { WINDOW } from './types'; | ||
|
|
||
| /** | ||
|
|
@@ -32,38 +31,34 @@ export function getNativeImplementation<T extends keyof CacheableImplementations | |
| return cached; | ||
| } | ||
|
|
||
| let impl = WINDOW[name] as CacheableImplementations[T]; | ||
| const cacheAndReturn = (impl: CacheableImplementations[T]) => (cachedImplementations[name] = impl.bind(WINDOW)); | ||
|
|
||
| const windowImpl = WINDOW[name] as CacheableImplementations[T]; | ||
|
|
||
| // Fast path to avoid DOM I/O | ||
| if (isNativeFunction(impl)) { | ||
| return (cachedImplementations[name] = impl.bind(WINDOW) as CacheableImplementations[T]); | ||
| if (isNativeFunction(windowImpl)) { | ||
| return cacheAndReturn(windowImpl); | ||
| } | ||
|
|
||
| const document = WINDOW.document; | ||
| // eslint-disable-next-line deprecation/deprecation | ||
| if (document && typeof document.createElement === 'function') { | ||
| try { | ||
| const sandbox = document.createElement('iframe'); | ||
| sandbox.hidden = true; | ||
| document.head.appendChild(sandbox); | ||
| const contentWindow = sandbox.contentWindow; | ||
| if (contentWindow?.[name]) { | ||
| impl = contentWindow[name] as CacheableImplementations[T]; | ||
| } | ||
| document.head.removeChild(sandbox); | ||
| } catch (e) { | ||
| // Could not create sandbox iframe, just use window.xxx | ||
| DEBUG_BUILD && debug.warn(`Could not create sandbox iframe for ${name} check, bailing to window.${name}: `, e); | ||
| } | ||
| const iframeImpl = getNativeImplementationFromIframe(name); | ||
| if (iframeImpl) { | ||
| return cacheAndReturn(iframeImpl); | ||
| } | ||
|
|
||
| // Sanity check: This _should_ not happen, but if it does, we just skip caching... | ||
| // This can happen e.g. in tests where fetch may not be available in the env, or similar. | ||
| if (!impl) { | ||
| return impl; | ||
| // This is a really weird fallback but here's what's going on: | ||
| // We're just being extra careful here. According to types, windowImpl is _always_ defined. | ||
| // However, in some very rare cases (for example test environments), it may in fact not be defined. | ||
| // In exactly this case, if we fail to get an iframeImpl, AND no windowImpl either, | ||
| // we skip caching and just return effectively undefined (despite types saying it's always defined) | ||
| // This basically tricks TS into thinking this function never returns `undefined` which | ||
| // for the most part is true. | ||
| if (!windowImpl) { | ||
| return windowImpl; // but actually return undefined | ||
| } | ||
|
|
||
| return (cachedImplementations[name] = impl.bind(WINDOW) as CacheableImplementations[T]); | ||
| // If _only_ iframeImpl is undefined and windowImpl is defined and not not native, we end up here | ||
| // In this case, we deliberately cache the windowImpl. | ||
| return cacheAndReturn(windowImpl); | ||
|
Comment on lines
+48
to
+61
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Writing this down in case we ever wonder why the hell this code path exists: This PR DID NOT change any prior behavior. I think this function was already flawed but for the scope of this PR, I'll not fix it right away. Two sketchy things:
This PR just more clearly call out this behaviour as it was quite hidden away in the prior implementation. I'll investigate if we can fix at least the latter flaw by returning |
||
| } | ||
|
|
||
| /** Clear a cached implementation. */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import { DEBUG_BUILD } from '../debug-build'; | ||
| import { GLOBAL_OBJ } from './worldwide'; | ||
| import { debug } from './debug-logger'; | ||
|
|
||
| const WINDOW = GLOBAL_OBJ as unknown as Window; | ||
|
|
||
| interface CacheableImplementations { | ||
| setTimeout: typeof WINDOW.setTimeout; | ||
| fetch: typeof WINDOW.fetch; | ||
| } | ||
|
|
||
| export function getNativeImplementationFromIframe<T extends keyof CacheableImplementations>(name: T) { | ||
| let impl = undefined; | ||
| const document = WINDOW.document; | ||
| // eslint-disable-next-line deprecation/deprecation | ||
| if (document && typeof document.createElement === 'function') { | ||
| try { | ||
| const sandbox = document.createElement('iframe'); | ||
| sandbox.hidden = true; | ||
| document.head.appendChild(sandbox); | ||
| const contentWindow = sandbox.contentWindow; | ||
| if (contentWindow?.[name]) { | ||
| impl = contentWindow[name] as CacheableImplementations[T]; | ||
| } | ||
| document.head.removeChild(sandbox); | ||
| } catch (e) { | ||
| // Could not create sandbox iframe, just use window.xxx | ||
| DEBUG_BUILD && debug.warn(`Could not create sandbox iframe for ${name} check, bailing to window.${name}: `, e); | ||
| } | ||
| } | ||
| return impl; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.