Skip to content

Commit a38594f

Browse files
authored
fix(core): Use makeDsn from core to extract the URL from DSN for filtering breadcrumbs (#4395)
1 parent ae7b03d commit a38594f

File tree

3 files changed

+57
-17
lines changed

3 files changed

+57
-17
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
### Fixes
1212

1313
- Use proper SDK name for Session Replay tags ([#4428](https://github.com/getsentry/sentry-react-native/pull/4428))
14+
- Use `makeDsn` from `core` to extract the URL from DSN avoiding unimplemented `URL.protocol` errors ([#4395]https://github.com/getsentry/sentry-react-native/pull/4395)
1415

1516
### Changes
1617

packages/core/src/js/sdk.tsx

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable complexity */
22
import type { Breadcrumb, BreadcrumbHint, Integration, Scope, SendFeedbackParams, UserFeedback } from '@sentry/core';
3-
import { captureFeedback, getClient, getGlobalScope, getIntegrationsToSetup, getIsolationScope, initAndBind, logger, stackParserFromStackParserOptions, withScope as coreWithScope } from '@sentry/core';
3+
import { captureFeedback, getClient, getGlobalScope, getIntegrationsToSetup, getIsolationScope, initAndBind, logger, makeDsn, stackParserFromStackParserOptions, withScope as coreWithScope } from '@sentry/core';
44
import {
55
defaultStackParser,
66
makeFetchTransport,
@@ -66,13 +66,13 @@ export function init(passedOptions: ReactNativeOptions): void {
6666
if (!dsn) {
6767
return undefined;
6868
}
69-
try {
70-
const url = new URL(dsn);
71-
return `${url.protocol}//${url.host}`;
72-
} catch (e) {
73-
logger.error('Failed to extract url from DSN', e);
69+
const dsnComponents = makeDsn(dsn);
70+
if (!dsnComponents) {
71+
logger.error('Failed to extract url from DSN: ', dsn);
7472
return undefined;
7573
}
74+
const port = dsnComponents.port ? `:${dsnComponents.port}` : '';
75+
return `${dsnComponents.protocol}://${dsnComponents.host}${port}`;
7676
};
7777

7878
const userBeforeBreadcrumb = safeFactory(passedOptions.beforeBreadcrumb, { loggerMessage: 'The beforeBreadcrumb threw an error' });

packages/core/test/sdk.test.ts

+50-11
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ describe('Tests the SDK functionality', () => {
321321
expect(result).toBeNull();
322322
});
323323

324-
it('should filters out dsn breadcrumbs', () => {
324+
it('should filter out dsn breadcrumbs', () => {
325325
(getDevServer as jest.Mock).mockReturnValue({ url: 'http://localhost:8081' });
326326

327327
const mockBeforeBreadcrumb = (breadcrumb: Breadcrumb, _hint?: BreadcrumbHint) => {
@@ -345,37 +345,76 @@ describe('Tests the SDK functionality', () => {
345345
expect(result).toBeNull();
346346
});
347347

348-
it('should keep breadcrumbs matching dsn if the url parsing fails for dsn', () => {
348+
it('should filter out dsn breadcrumbs that the ports match', () => {
349349
(getDevServer as jest.Mock).mockReturnValue({ url: 'http://localhost:8081' });
350350

351351
const mockBeforeBreadcrumb = (breadcrumb: Breadcrumb, _hint?: BreadcrumbHint) => {
352352
return breadcrumb;
353353
};
354354

355-
// Mock the URL constructor to throw an exception for this test case
356-
const originalURL = (global as any).URL;
357-
jest.spyOn(global as any, 'URL').mockImplementationOnce(() => {
358-
throw new Error('Failed to parse DSN URL');
359-
});
355+
const passedOptions = {
356+
dsn: 'https://[email protected]:8181/1234567',
357+
beforeBreadcrumb: mockBeforeBreadcrumb,
358+
};
359+
360+
init(passedOptions);
361+
362+
const breadcrumb: Breadcrumb = {
363+
type: 'http',
364+
data: { url: 'https://selfhosted.app.server:8181/api' },
365+
};
366+
367+
const result = usedOptions()?.beforeBreadcrumb!(breadcrumb);
368+
369+
expect(result).toBeNull();
370+
});
371+
372+
it('should keep breadcrumbs if the ports do not match', () => {
373+
(getDevServer as jest.Mock).mockReturnValue({ url: 'http://localhost:8081' });
374+
375+
const mockBeforeBreadcrumb = (breadcrumb: Breadcrumb, _hint?: BreadcrumbHint) => {
376+
return breadcrumb;
377+
};
360378

361379
const passedOptions = {
362-
dsn: 'https://[email protected]/1234567',
380+
dsn: 'https://[email protected]:8181/1234567',
363381
beforeBreadcrumb: mockBeforeBreadcrumb,
364382
};
365383

366384
init(passedOptions);
367385

368386
const breadcrumb: Breadcrumb = {
369387
type: 'http',
370-
data: { url: 'https://def.ingest.sentry.io/1234567' },
388+
data: { url: 'https://selfhosted.app.server:8080/api' },
371389
};
372390

373391
const result = usedOptions()?.beforeBreadcrumb!(breadcrumb);
374392

375393
expect(result).toEqual(breadcrumb);
394+
});
395+
396+
it('should keep breadcrumbs if the url parsing fails for dsn', () => {
397+
(getDevServer as jest.Mock).mockReturnValue({ url: 'http://localhost:8081' });
398+
399+
const mockBeforeBreadcrumb = (breadcrumb: Breadcrumb, _hint?: BreadcrumbHint) => {
400+
return breadcrumb;
401+
};
402+
403+
const passedOptions = {
404+
dsn: 'invalid-dsn',
405+
beforeBreadcrumb: mockBeforeBreadcrumb,
406+
};
407+
408+
init(passedOptions);
376409

377-
// Restore the original URL constructor
378-
(global as any).URL = originalURL;
410+
const breadcrumb: Breadcrumb = {
411+
type: 'http',
412+
data: { url: 'https://def.ingest.sentry.io/1234567' },
413+
};
414+
415+
const result = usedOptions()?.beforeBreadcrumb!(breadcrumb);
416+
417+
expect(result).toEqual(breadcrumb);
379418
});
380419

381420
it('should keep non dev server or dsn breadcrumbs', () => {

0 commit comments

Comments
 (0)