@@ -26,8 +26,8 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions {
2626 public static let includedViewClasses : Set < String > = [ ]
2727
2828 // Network capture configuration defaults
29- public static let networkDetailAllowUrls : [ Any ] = [ ]
30- public static let networkDetailDenyUrls : [ Any ] = [ ]
29+ public static let networkDetailAllowUrls : [ SentryUrlMatchable ] = [ ]
30+ public static let networkDetailDenyUrls : [ SentryUrlMatchable ] = [ ]
3131 public static let networkCaptureBodies : Bool = true
3232 public static let networkRequestHeaders : [ String ] = [ " Content-Type " , " Content-Length " , " Accept " ]
3333 public static let networkResponseHeaders : [ String ] = [ " Content-Type " , " Content-Length " , " Accept " ]
@@ -301,14 +301,14 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions {
301301
302302 /**
303303 * A list of URL patterns to capture request and response details for during session replay.
304- *
304+ *
305305 * When non-empty, network requests with URLs matching any of these patterns will have their
306306 * headers and bodies captured for session replay.
307- *
308- * Supports both String and NSRegularExpression patterns (See [JavaScript SDK](https://github.com/getsentry/sentry-javascript/blob/6fb1ee139a92a6055b52b0bbf5136fa0e5a9353f/packages/core/src/utils/string.ts#L114-L119)) :
307+ *
308+ * Supports both String and NSRegularExpression patterns:
309309 * - String: Uses substring contains
310310 * - NSRegularExpression: Uses full regex matching
311- *
311+ *
312312 * Default: empty array (network detail capture disabled)
313313 *
314314 * Example:
@@ -335,27 +335,41 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions {
335335 * - Note: Request and response bodies are truncated to 150KB maximum.
336336 * - Note: See ``SentryReplayOptions.DefaultValues.networkDetailAllowUrls`` for the default value.
337337 */
338- public var networkDetailAllowUrls : [ Any ]
338+ public var networkDetailAllowUrls : [ SentryUrlMatchable ]
339+
340+ /// Objective-C bridge for networkDetailAllowUrls.
341+ /// - Warning: This property exists for Objective-C compatibility only. Swift code should use
342+ /// `networkDetailAllowUrls` directly. This is not part of the public API.
343+ @objc ( networkDetailAllowUrls) public var networkDetailAllowUrlsForObjC : NSArray {
344+ return networkDetailAllowUrls as NSArray
345+ }
339346
340347 /**
341348 * A list of URL patterns to exclude from network detail capture during session replay.
342- *
349+ *
343350 * URLs matching any pattern in this array will NOT have their headers and bodies captured,
344- * even if they match patterns in `networkDetailAllowUrls`. This provides fine-grained
351+ * even if they match patterns in `networkDetailAllowUrls`. This provides fine-grained
345352 * control for excluding sensitive endpoints from capture.
346- *
347- * Supports both String and NSRegularExpression patterns (mirroring JavaScript SDK) :
348- * - String: Uses substring containment check (like JavaScript's `includes()`)
353+ *
354+ * Supports both String and NSRegularExpression patterns:
355+ * - String: Uses substring match
349356 * - NSRegularExpression: Uses full regex matching
350- *
357+ *
351358 * Default: empty array (no URLs explicitly denied)
352359 *
353360 * Examples:
354361 * - String patterns: "/auth/", "/payment/", "password", ".internal."
355362 * - NSRegularExpression patterns: Use try NSRegularExpression(pattern:) to create regex objects
356363 * - Mixed arrays are supported with both types
357364 */
358- public var networkDetailDenyUrls : [ Any ]
365+ public var networkDetailDenyUrls : [ SentryUrlMatchable ]
366+
367+ /// Objective-C bridge for networkDetailDenyUrls.
368+ /// - Warning: This property exists for Objective-C compatibility only. Swift code should use
369+ /// `networkDetailDenyUrls` directly. This is not part of the public API.
370+ @objc ( networkDetailDenyUrls) public var networkDetailDenyUrlsForObjC : NSArray {
371+ return networkDetailDenyUrls as NSArray
372+ }
359373
360374 /**
361375 * Whether to capture request and response bodies for allowed URLs.
@@ -496,45 +510,35 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions {
496510 return false
497511 }
498512
499- if matchesAnyPattern ( urlString, patterns : networkDetailDenyUrls) {
513+ if matches ( url : urlString, against : networkDetailDenyUrls) {
500514 return false
501515 }
502516
503- return matchesAnyPattern ( urlString, patterns : networkDetailAllowUrls)
517+ return matches ( url : urlString, against : networkDetailAllowUrls)
504518 }
505519
506520 /**
507521 * Helper method to check if a URL string matches any pattern in a list.
508522 *
509523 * Supports both String and NSRegularExpression patterns:
510- * - String: Uses substring containment check (like JavaScript's includes())
524+ * - String: Uses substring match
511525 * - NSRegularExpression: Uses full regex matching
512526 *
513527 * - Parameters:
514- * - urlString : The URL string to test
515- * - patterns : Array of String or NSRegularExpression patterns
528+ * - url : The URL string to test
529+ * - matchers : Array of SentryUrlMatchable patterns
516530 * - Returns: `true` if the URL matches any pattern, `false` otherwise
517531 */
518- private func matchesAnyPattern( _ urlString: String , patterns: [ Any ] ) -> Bool {
519- for pattern in patterns {
520- if let stringPattern = pattern as? String {
521- // String provided: substring match
522- // Filter out empty strings and whitespace-only strings
523- let trimmed = stringPattern. trimmingCharacters ( in: . whitespacesAndNewlines)
524- guard !trimmed. isEmpty else { continue }
525-
526- if urlString. contains ( stringPattern) {
527- return true
528- }
529- } else if let regexPattern = pattern as? NSRegularExpression {
530- // NSRegularExpression: use regex matching
531- let range = NSRange ( location: 0 , length: urlString. utf16. count)
532- if regexPattern. firstMatch ( in: urlString, options: [ ] , range: range) != nil {
533- return true
534- }
532+ private func matches( url: String , against matchers: [ SentryUrlMatchable ] ) -> Bool {
533+ matchers. contains { matcher in
534+ switch matcher. asSentryUrlMatcher {
535+ case . string( let pattern) :
536+ return url. contains ( pattern)
537+ case . regex( let regex) :
538+ let range = NSRange ( url. startIndex... , in: url)
539+ return regex. firstMatch ( in: url, range: range) != nil
535540 }
536541 }
537- return false
538542 }
539543
540544 /**
@@ -601,11 +605,11 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions {
601605 maximumDuration: ( dictionary [ " maximumDuration " ] as? NSNumber ) ? . doubleValue,
602606 excludedViewClasses: ( dictionary [ " excludedViewClasses " ] as? [ String ] ) . map { Set ( $0) } ,
603607 includedViewClasses: ( dictionary [ " includedViewClasses " ] as? [ String ] ) . map { Set ( $0) } ,
604- networkDetailAllowUrls: Self . validateNetworkDetailUrlPatterns ( from : dictionary [ " networkDetailAllowUrls " ] ) ,
605- networkDetailDenyUrls: Self . validateNetworkDetailUrlPatterns ( from : dictionary [ " networkDetailDenyUrls " ] ) ,
608+ networkDetailAllowUrls: SentryUrlMatcher . convertFromAny ( dictionary [ " networkDetailAllowUrls " ] ) ,
609+ networkDetailDenyUrls: SentryUrlMatcher . convertFromAny ( dictionary [ " networkDetailDenyUrls " ] ) ,
606610 networkCaptureBodies: ( dictionary [ " networkCaptureBodies " ] as? NSNumber ) ? . boolValue,
607- networkRequestHeaders: Self . parseStringArray ( from : dictionary [ " networkRequestHeaders " ] ) ,
608- networkResponseHeaders: Self . parseStringArray ( from : dictionary [ " networkResponseHeaders " ] )
611+ networkRequestHeaders: ( dictionary [ " networkRequestHeaders " ] as? [ Any ] ) ? . compactMap { $0 as? String } ,
612+ networkResponseHeaders: ( dictionary [ " networkResponseHeaders " ] as? [ Any ] ) ? . compactMap { $0 as? String }
609613 )
610614 }
611615
@@ -661,72 +665,6 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions {
661665 )
662666 }
663667
664- /**
665- * Helper method to parse and filter string arrays from dictionary configuration.
666- *
667- * Filters out non-string entries from mixed arrays while preserving valid strings.
668- * Returns nil when the input is not an array type, allowing callers to fall back to defaults.
669- *
670- * - Parameter value: The value from the dictionary to parse
671- * - Returns: Filtered array of strings, or nil if input is not an array
672- */
673- private static func parseStringArray( from value: Any ? ) -> [ String ] ? {
674- guard let array = value as? [ Any ] else {
675- return nil
676- }
677- return array. compactMap { $0 as? String }
678- }
679-
680- /**
681- * Validates developer-provided NetworkDetail URL patterns and returns a subset of only valid entries.
682- *
683- * Accepts both String and NSRegularExpression objects.
684- * Filters out invalid entries and preserves valid patterns.
685- * Filters out empty strings and whitespace-only strings.
686- *
687- * - Parameter value: The value from the dictionary to parse
688- * - Returns: Filtered array of String and NSRegularExpression patterns, or nil if input is not an array
689- */
690- private static func validateNetworkDetailUrlPatterns( from value: Any ? ) -> [ Any ] ? {
691- guard let array = value as? [ Any ] else {
692- if let nonNilValue = value {
693- SentrySDKLog . log ( message: " Invalid networkDetail URL pattern configuration: expected array, got \( type ( of: nonNilValue) ) " ,
694- andLevel: . warning)
695- }
696- return nil
697- }
698-
699- var validPatterns : [ Any ] = [ ]
700- var invalidCount = 0
701-
702- for (index, element) in array. enumerated ( ) {
703- if let stringElement = element as? String {
704- // Filter out empty strings and whitespace-only strings
705- let trimmed = stringElement. trimmingCharacters ( in: . whitespacesAndNewlines)
706- if trimmed. isEmpty {
707- SentrySDKLog . log ( message: " Invalid networkDetail URL pattern at index \( index) : empty or whitespace-only string discarded " ,
708- andLevel: . warning)
709- invalidCount += 1
710- } else {
711- validPatterns. append ( trimmed)
712- }
713- } else if let regexElement = element as? NSRegularExpression {
714- validPatterns. append ( regexElement)
715- } else {
716- SentrySDKLog . log ( message: " Invalid networkDetail URL pattern at index \( index) : expected String or NSRegularExpression, got \( type ( of: element) ) " ,
717- andLevel: . warning)
718- invalidCount += 1
719- }
720- }
721-
722- if invalidCount > 0 {
723- SentrySDKLog . log ( message: " NetworkDetail URL patterns: \( invalidCount) invalid entries discarded, \( validPatterns. count) valid patterns retained " ,
724- andLevel: . info)
725- }
726-
727- return validPatterns
728- }
729-
730668 // swiftlint:disable:next function_parameter_count cyclomatic_complexity
731669 private init (
732670 sessionSampleRate: Float ? ,
@@ -745,8 +683,8 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions {
745683 maximumDuration: TimeInterval ? ,
746684 excludedViewClasses: Set < String > ? = nil ,
747685 includedViewClasses: Set < String > ? = nil ,
748- networkDetailAllowUrls: [ Any ] ? = nil ,
749- networkDetailDenyUrls: [ Any ] ? = nil ,
686+ networkDetailAllowUrls: [ SentryUrlMatchable ] ? = nil ,
687+ networkDetailDenyUrls: [ SentryUrlMatchable ] ? = nil ,
750688 networkCaptureBodies: Bool ? = nil ,
751689 networkRequestHeaders: [ String ] ? = nil ,
752690 networkResponseHeaders: [ String ] ? = nil
@@ -767,8 +705,8 @@ public class SentryReplayOptions: NSObject, SentryRedactOptions {
767705 self . maximumDuration = maximumDuration ?? DefaultValues . maximumDuration
768706 self . excludedViewClasses = excludedViewClasses ?? DefaultValues . excludedViewClasses
769707 self . includedViewClasses = includedViewClasses ?? DefaultValues . includedViewClasses
770- self . networkDetailAllowUrls = Self . validateNetworkDetailUrlPatterns ( from : networkDetailAllowUrls) ?? DefaultValues . networkDetailAllowUrls
771- self . networkDetailDenyUrls = Self . validateNetworkDetailUrlPatterns ( from : networkDetailDenyUrls) ?? DefaultValues . networkDetailDenyUrls
708+ self . networkDetailAllowUrls = networkDetailAllowUrls ?? DefaultValues . networkDetailAllowUrls
709+ self . networkDetailDenyUrls = networkDetailDenyUrls ?? DefaultValues . networkDetailDenyUrls
772710 self . networkCaptureBodies = networkCaptureBodies ?? DefaultValues . networkCaptureBodies
773711 self . _networkRequestHeaders = Self . mergeWithDefaultHeaders ( networkRequestHeaders, defaults: DefaultValues . networkRequestHeaders)
774712 self . _networkResponseHeaders = Self . mergeWithDefaultHeaders ( networkResponseHeaders, defaults: DefaultValues . networkResponseHeaders)
0 commit comments