Files
Pulse/Sources/PulseCore/NetworkLoggerEvent.swift
T

190 lines
7.6 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// The MIT License (MIT)
//
// Copyright (c) 20202022 Alexander Grebenyuk (github.com/kean).
import Foundation
public struct NetworkLoggerRequest: Codable {
public let url: URL?
public let httpMethod: String?
public let headers: [String: String]
/// `URLRequest.CachePolicy` raw value
public let cachePolicy: UInt
public let timeoutInterval: TimeInterval
public let allowsCellularAccess: Bool
public let allowsExpensiveNetworkAccess: Bool
public let allowsConstrainedNetworkAccess: Bool
public let httpShouldHandleCookies: Bool
public let httpShouldUsePipelining: Bool
public init(urlRequest: URLRequest) {
self.url = urlRequest.url
self.httpMethod = urlRequest.httpMethod
self.headers = urlRequest.allHTTPHeaderFields ?? [:]
self.cachePolicy = urlRequest.cachePolicy.rawValue
self.timeoutInterval = urlRequest.timeoutInterval
self.allowsCellularAccess = urlRequest.allowsCellularAccess
self.allowsExpensiveNetworkAccess = urlRequest.allowsExpensiveNetworkAccess
self.allowsConstrainedNetworkAccess = urlRequest.allowsConstrainedNetworkAccess
self.httpShouldHandleCookies = urlRequest.httpShouldHandleCookies
self.httpShouldUsePipelining = urlRequest.httpShouldUsePipelining
}
}
public struct NetworkLoggerResponse: Codable {
public let statusCode: Int?
public let contentType: String?
public let expectedContentLength: Int64?
public let headers: [String: String]
public init(urlResponse: URLResponse) {
let httpResponse = urlResponse as? HTTPURLResponse
self.statusCode = httpResponse?.statusCode
self.contentType = urlResponse.mimeType
self.expectedContentLength = urlResponse.expectedContentLength
self.headers = httpResponse?.allHeaderFields as? [String: String] ?? [:]
}
}
public struct NetworkLoggerError: Codable {
public let code: Int
public let domain: String
public let localizedDescription: String
public init(error: Error) {
let error = error as NSError
self.code = error.code
self.domain = error.domain
self.localizedDescription = error.localizedDescription
}
}
public struct NetworkLoggerMetrics: Codable {
public let taskInterval: DateInterval
public let redirectCount: Int
public let transactions: [NetworkLoggerTransactionMetrics]
public init(metrics: URLSessionTaskMetrics) {
self.taskInterval = metrics.taskInterval
self.redirectCount = metrics.redirectCount
self.transactions = metrics.transactionMetrics.map(NetworkLoggerTransactionMetrics.init)
}
}
public struct NetworkLoggerTransactionMetrics: Codable {
public let request: NetworkLoggerRequest?
public let response: NetworkLoggerResponse?
public let fetchStartDate: Date?
public let domainLookupStartDate: Date?
public let domainLookupEndDate: Date?
public let connectStartDate: Date?
public let secureConnectionStartDate: Date?
public let secureConnectionEndDate: Date?
public let connectEndDate: Date?
public let requestStartDate: Date?
public let requestEndDate: Date?
public let responseStartDate: Date?
public let responseEndDate: Date?
public let networkProtocolName: String?
public let isProxyConnection: Bool
public let isReusedConnection: Bool
/// `URLSessionTaskMetrics.ResourceFetchType` enum raw value
public let resourceFetchType: Int
public let details: NetworkLoggerTransactionDetailedMetrics?
public init(metrics: URLSessionTaskTransactionMetrics) {
self.request = NetworkLoggerRequest(urlRequest: metrics.request)
self.response = metrics.response.map(NetworkLoggerResponse.init)
self.fetchStartDate = metrics.fetchStartDate
self.domainLookupStartDate = metrics.domainLookupStartDate
self.domainLookupEndDate = metrics.domainLookupEndDate
self.connectStartDate = metrics.connectStartDate
self.secureConnectionStartDate = metrics.secureConnectionStartDate
self.secureConnectionEndDate = metrics.secureConnectionEndDate
self.connectEndDate = metrics.connectEndDate
self.requestStartDate = metrics.requestStartDate
self.requestEndDate = metrics.requestEndDate
self.responseStartDate = metrics.responseStartDate
self.responseEndDate = metrics.responseEndDate
self.networkProtocolName = metrics.networkProtocolName
self.isProxyConnection = metrics.isProxyConnection
self.isReusedConnection = metrics.isReusedConnection
self.resourceFetchType = metrics.resourceFetchType.rawValue
self.details = NetworkLoggerTransactionDetailedMetrics(metrics: metrics)
}
}
public struct NetworkLoggerTransactionDetailedMetrics: Codable {
public let countOfRequestHeaderBytesSent: Int64
public let countOfRequestBodyBytesSent: Int64
public let countOfRequestBodyBytesBeforeEncoding: Int64
public let countOfResponseHeaderBytesReceived: Int64
public let countOfResponseBodyBytesReceived: Int64
public let countOfResponseBodyBytesAfterDecoding: Int64
public let localAddress: String?
public let remoteAddress: String?
public let isCellular: Bool
public let isExpensive: Bool
public let isConstrained: Bool
public let isMultipath: Bool
public let localPort: Int?
public let remotePort: Int?
/// `tls_protocol_version_t` enum raw value
public let negotiatedTLSProtocolVersion: UInt16?
/// `tls_ciphersuite_t` enum raw value
public let negotiatedTLSCipherSuite: UInt16?
public init(metrics: URLSessionTaskTransactionMetrics) {
self.countOfRequestHeaderBytesSent = metrics.countOfRequestHeaderBytesSent
self.countOfRequestBodyBytesSent = metrics.countOfRequestBodyBytesSent
self.countOfRequestBodyBytesBeforeEncoding = metrics.countOfRequestBodyBytesBeforeEncoding
self.countOfResponseHeaderBytesReceived = metrics.countOfResponseHeaderBytesReceived
self.countOfResponseBodyBytesReceived = metrics.countOfResponseBodyBytesReceived
self.countOfResponseBodyBytesAfterDecoding = metrics.countOfResponseBodyBytesAfterDecoding
self.localAddress = metrics.localAddress
self.remoteAddress = metrics.remoteAddress
self.isCellular = metrics.isCellular
self.isExpensive = metrics.isExpensive
self.isConstrained = metrics.isConstrained
self.isMultipath = metrics.isMultipath
self.localPort = metrics.localPort
self.remotePort = metrics.remotePort
self.negotiatedTLSProtocolVersion = metrics.negotiatedTLSProtocolVersion?.rawValue
self.negotiatedTLSCipherSuite = metrics.negotiatedTLSCipherSuite?.rawValue
}
}
public enum NetworkLoggerTaskType: String, Codable {
case dataTask
case downloadTask
case uploadTask
case streamTask
case webSocketTask
public init(task: URLSessionTask) {
switch task {
case task as URLSessionDataTask: self = .dataTask
case task as URLSessionDownloadTask: self = .downloadTask
case task as URLSessionStreamTask: self = .streamTask
case task as URLSessionUploadTask: self = .uploadTask
case task as URLSessionWebSocketTask: self = .webSocketTask
default:
assertionFailure("Unknown task type: \(task)")
self = .dataTask
}
}
}
private extension URLSessionConfiguration {
var headers: [String: String]? {
guard let headers = httpAdditionalHeaders else {
return nil
}
var output: [String: String] = [:]
for (key, value) in headers {
output["\(key)"] = "\(value)"
}
return output
}
}