-
Notifications
You must be signed in to change notification settings - Fork 134
/
Copy pathDatadogURLSessionDelegate.swift
142 lines (124 loc) · 6.39 KB
/
DatadogURLSessionDelegate.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2019-Present Datadog, Inc.
*/
import Foundation
@available(*, deprecated, message: "Use `URLSessionInstrumentation.enable(with:)` instead.")
public typealias DDURLSessionDelegate = DatadogURLSessionDelegate
/// An interface for forwarding `URLSessionDelegate` calls to `DDURLSessionDelegate`.
/// The implementation must ensure that required methods are called on the `ddURLSessionDelegate`.
@objc
@available(*, deprecated, message: "Use `URLSessionInstrumentation.enable(with:)` instead.")
public protocol __URLSessionDelegateProviding: URLSessionDelegate {
/// Datadog delegate object.
///
/// The class implementing `DDURLSessionDelegateProviding` must ensure that following method calls are forwarded to `ddURLSessionDelegate`:
/// - `func urlSession(_:task:didFinishCollecting:)`
/// - `func urlSession(_:task:didCompleteWithError:)`
/// - `func urlSession(_:dataTask:didReceive:)`
var ddURLSessionDelegate: DatadogURLSessionDelegate { get }
}
/// The `URLSession` delegate object which enables network requests instrumentation. **It must be
/// used together with** `DatadogRUM` or `DatadogTrace`.
///
/// All requests made with the `URLSession` instrumented with this delegate will be intercepted by the SDK.
@objc
@available(*, deprecated, message: "Use `URLSessionInstrumentation.enable(with:)` instead.")
open class DatadogURLSessionDelegate: NSObject, URLSessionDataDelegate {
var interceptor: URLSessionInterceptor? {
let core = self.core ?? CoreRegistry.default
return URLSessionInterceptor.shared(in: core)
}
let swizzler = URLSessionSwizzler()
/// The instance of the SDK core notified by this delegate.
///
/// It must be a weak reference, because `URLSessionDelegate` can last longer than core instance.
/// Any `URLSession` will retain its delegate until `.invalidateAndCancel()` is called.
private weak var core: DatadogCoreProtocol?
@objc
override public init() {
core = nil
super.init()
try? swizzle(firstPartyHosts: .init())
}
/// Automatically tracked hosts can be customized per instance with this initializer.
///
/// **NOTE:** If `trackURLSession(firstPartyHostsWithHeaderTypes:)` is never called, automatic tracking will **not** take place.
///
/// - Parameter additionalFirstPartyHostsWithHeaderTypes: these hosts are tracked **in addition to** what was
/// passed to `DatadogConfiguration.Builder` via `trackURLSession(firstPartyHostsWithHeaderTypes:)`
public convenience init(additionalFirstPartyHostsWithHeaderTypes: [String: Set<TracingHeaderType>]) {
self.init(
in: nil,
additionalFirstPartyHostsWithHeaderTypes: additionalFirstPartyHostsWithHeaderTypes
)
}
/// Automatically tracked hosts can be customized per instance with this initializer.
///
/// **NOTE:** If `trackURLSession(firstPartyHosts:)` is never called, automatic tracking will **not** take place.
///
/// - Parameter additionalFirstPartyHosts: these hosts are tracked **in addition to** what was
/// passed to `DatadogConfiguration.Builder` via `trackURLSession(firstPartyHosts:)`
@objc
public convenience init(additionalFirstPartyHosts: Set<String>) {
self.init(
in: nil,
additionalFirstPartyHostsWithHeaderTypes: additionalFirstPartyHosts.reduce(into: [:], { partialResult, host in
partialResult[host] = [.datadog, .tracecontext]
})
)
}
/// Automatically tracked hosts can be customized per instance with this initializer.
///
/// **NOTE:** If `trackURLSession(firstPartyHostsWithHeaderTypes:)` is never called, automatic tracking will **not** take place.
///
/// - Parameters:
/// - core: Datadog SDK instance (or `nil` to use default SDK instance).
/// - additionalFirstPartyHosts: these hosts are tracked **in addition to** what was
/// passed to `DatadogConfiguration.Builder` via `trackURLSession(firstPartyHosts:)`
public init(
in core: DatadogCoreProtocol? = nil,
additionalFirstPartyHostsWithHeaderTypes: [String: Set<TracingHeaderType>] = [:]
) {
self.core = core
super.init()
try? swizzle(firstPartyHosts: FirstPartyHosts(additionalFirstPartyHostsWithHeaderTypes))
}
open func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {
interceptor?.task(task, didFinishCollecting: metrics)
}
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
// NOTE: This delegate method is only called for `URLSessionTasks` created without the completion handler.
interceptor?.task(dataTask, didReceive: data)
}
open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
// NOTE: This delegate method is only called for `URLSessionTasks` created without the completion handler.
interceptor?.task(task, didCompleteWithError: error)
}
private func swizzle(firstPartyHosts: FirstPartyHosts) throws {
try swizzler.swizzle(
interceptResume: { [weak self] task in
guard
let interceptor = self?.interceptor,
let provider = task.dd.delegate as? __URLSessionDelegateProviding,
provider.ddURLSessionDelegate == self // intercept task with self as delegate
else {
return
}
if let currentRequest = task.currentRequest {
let request = interceptor.intercept(request: currentRequest, additionalFirstPartyHosts: firstPartyHosts)
task.dd.override(currentRequest: request)
}
interceptor.intercept(task: task, additionalFirstPartyHosts: firstPartyHosts)
}
)
}
deinit {
swizzler.unswizzle()
}
}
@available(*, deprecated, message: "Use `URLSessionInstrumentation.enable(with:)` instead.")
extension DatadogURLSessionDelegate: __URLSessionDelegateProviding {
public var ddURLSessionDelegate: DatadogURLSessionDelegate { self }
}