| | |
| | | /// `Session` creates and manages Alamofire's `Request` types during their lifetimes. It also provides common |
| | | /// functionality for all `Request`s, including queuing, interception, trust management, redirect handling, and response |
| | | /// cache handling. |
| | | open class Session { |
| | | open class Session: @unchecked Sendable { |
| | | /// Shared singleton instance used by all `AF.request` APIs. Cannot be modified. |
| | | public static let `default` = Session() |
| | | |
| | |
| | | public let serializationQueue: DispatchQueue |
| | | /// `RequestInterceptor` used for all `Request` created by the instance. `RequestInterceptor`s can also be set on a |
| | | /// per-`Request` basis, in which case the `Request`'s interceptor takes precedence over this value. |
| | | public let interceptor: RequestInterceptor? |
| | | public let interceptor: (any RequestInterceptor)? |
| | | /// `ServerTrustManager` instance used to evaluate all trust challenges and provide certificate and key pinning. |
| | | public let serverTrustManager: ServerTrustManager? |
| | | /// `RedirectHandler` instance used to provide customization for request redirection. |
| | | public let redirectHandler: RedirectHandler? |
| | | public let redirectHandler: (any RedirectHandler)? |
| | | /// `CachedResponseHandler` instance used to provide customization of cached response handling. |
| | | public let cachedResponseHandler: CachedResponseHandler? |
| | | /// `CompositeEventMonitor` used to compose Alamofire's `defaultEventMonitors` and any passed `EventMonitor`s. |
| | | public let cachedResponseHandler: (any CachedResponseHandler)? |
| | | /// `CompositeEventMonitor` used to compose any passed `EventMonitor`s. |
| | | public let eventMonitor: CompositeEventMonitor |
| | | /// `EventMonitor`s included in all instances. `[AlamofireNotifications()]` by default. |
| | | public let defaultEventMonitors: [EventMonitor] = [AlamofireNotifications()] |
| | | /// `EventMonitor`s included in all instances unless overwritten. `[AlamofireNotifications()]` by default. |
| | | @available(*, deprecated, message: "Use [AlamofireNotifications()] directly.") |
| | | public let defaultEventMonitors: [any EventMonitor] = [AlamofireNotifications()] |
| | | |
| | | /// Internal map between `Request`s and any `URLSessionTasks` that may be in flight for them. |
| | | var requestTaskMap = RequestTaskMap() |
| | |
| | | /// default. |
| | | /// - cachedResponseHandler: `CachedResponseHandler` to be used by all `Request`s created by this instance. |
| | | /// `nil` by default. |
| | | /// - eventMonitors: Additional `EventMonitor`s used by the instance. Alamofire always adds a |
| | | /// `AlamofireNotifications` `EventMonitor` to the array passed here. `[]` by default. |
| | | /// - eventMonitors: `EventMonitor`s used by the instance. `[AlamofireNotifications()]` by default. |
| | | public init(session: URLSession, |
| | | delegate: SessionDelegate, |
| | | rootQueue: DispatchQueue, |
| | | startRequestsImmediately: Bool = true, |
| | | requestQueue: DispatchQueue? = nil, |
| | | serializationQueue: DispatchQueue? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | serverTrustManager: ServerTrustManager? = nil, |
| | | redirectHandler: RedirectHandler? = nil, |
| | | cachedResponseHandler: CachedResponseHandler? = nil, |
| | | eventMonitors: [EventMonitor] = []) { |
| | | redirectHandler: (any RedirectHandler)? = nil, |
| | | cachedResponseHandler: (any CachedResponseHandler)? = nil, |
| | | eventMonitors: [any EventMonitor] = [AlamofireNotifications()]) { |
| | | precondition(session.configuration.identifier == nil, |
| | | "Alamofire does not support background URLSessionConfigurations.") |
| | | precondition(session.delegateQueue.underlyingQueue === rootQueue, |
| | |
| | | self.serverTrustManager = serverTrustManager |
| | | self.redirectHandler = redirectHandler |
| | | self.cachedResponseHandler = cachedResponseHandler |
| | | eventMonitor = CompositeEventMonitor(monitors: defaultEventMonitors + eventMonitors) |
| | | eventMonitor = CompositeEventMonitor(monitors: eventMonitors) |
| | | delegate.eventMonitor = eventMonitor |
| | | delegate.stateProvider = self |
| | | } |
| | |
| | | /// default. |
| | | /// - cachedResponseHandler: `CachedResponseHandler` to be used by all `Request`s created by this instance. |
| | | /// `nil` by default. |
| | | /// - eventMonitors: Additional `EventMonitor`s used by the instance. Alamofire always adds a |
| | | /// `AlamofireNotifications` `EventMonitor` to the array passed here. `[]` by default. |
| | | /// - eventMonitors: `EventMonitor`s used by the instance. `[AlamofireNotifications()]` by default. |
| | | public convenience init(configuration: URLSessionConfiguration = URLSessionConfiguration.af.default, |
| | | delegate: SessionDelegate = SessionDelegate(), |
| | | rootQueue: DispatchQueue = DispatchQueue(label: "org.alamofire.session.rootQueue"), |
| | | startRequestsImmediately: Bool = true, |
| | | requestQueue: DispatchQueue? = nil, |
| | | serializationQueue: DispatchQueue? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | serverTrustManager: ServerTrustManager? = nil, |
| | | redirectHandler: RedirectHandler? = nil, |
| | | cachedResponseHandler: CachedResponseHandler? = nil, |
| | | eventMonitors: [EventMonitor] = []) { |
| | | redirectHandler: (any RedirectHandler)? = nil, |
| | | cachedResponseHandler: (any CachedResponseHandler)? = nil, |
| | | eventMonitors: [any EventMonitor] = [AlamofireNotifications()]) { |
| | | precondition(configuration.identifier == nil, "Alamofire does not support background URLSessionConfigurations.") |
| | | |
| | | // Retarget the incoming rootQueue for safety, unless it's the main queue, which we know is safe. |
| | |
| | | /// |
| | | /// - Parameters: |
| | | /// - action: Closure to perform with all `Request`s. |
| | | public func withAllRequests(perform action: @escaping (Set<Request>) -> Void) { |
| | | public func withAllRequests(perform action: @escaping @Sendable (Set<Request>) -> Void) { |
| | | rootQueue.async { |
| | | action(self.activeRequests) |
| | | } |
| | |
| | | /// - Parameters: |
| | | /// - queue: `DispatchQueue` on which the completion handler is run. `.main` by default. |
| | | /// - completion: Closure to be called when all `Request`s have been cancelled. |
| | | public func cancelAllRequests(completingOnQueue queue: DispatchQueue = .main, completion: (() -> Void)? = nil) { |
| | | public func cancelAllRequests(completingOnQueue queue: DispatchQueue = .main, completion: (@Sendable () -> Void)? = nil) { |
| | | withAllRequests { requests in |
| | | requests.forEach { $0.cancel() } |
| | | queue.async { |
| | |
| | | // MARK: - DataRequest |
| | | |
| | | /// Closure which provides a `URLRequest` for mutation. |
| | | public typealias RequestModifier = (inout URLRequest) throws -> Void |
| | | public typealias RequestModifier = @Sendable (inout URLRequest) throws -> Void |
| | | |
| | | struct RequestConvertible: URLRequestConvertible { |
| | | let url: URLConvertible |
| | | let url: any URLConvertible |
| | | let method: HTTPMethod |
| | | let parameters: Parameters? |
| | | let encoding: ParameterEncoding |
| | | let encoding: any ParameterEncoding |
| | | let headers: HTTPHeaders? |
| | | let requestModifier: RequestModifier? |
| | | |
| | |
| | | /// parameters. `nil` by default. |
| | | /// |
| | | /// - Returns: The created `DataRequest`. |
| | | open func request(_ convertible: URLConvertible, |
| | | open func request(_ convertible: any URLConvertible, |
| | | method: HTTPMethod = .get, |
| | | parameters: Parameters? = nil, |
| | | encoding: ParameterEncoding = URLEncoding.default, |
| | | encoding: any ParameterEncoding = URLEncoding.default, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | requestModifier: RequestModifier? = nil) -> DataRequest { |
| | | let convertible = RequestConvertible(url: convertible, |
| | | method: method, |
| | |
| | | return request(convertible, interceptor: interceptor) |
| | | } |
| | | |
| | | struct RequestEncodableConvertible<Parameters: Encodable>: URLRequestConvertible { |
| | | let url: URLConvertible |
| | | struct RequestEncodableConvertible<Parameters: Encodable & Sendable>: URLRequestConvertible { |
| | | let url: any URLConvertible |
| | | let method: HTTPMethod |
| | | let parameters: Parameters? |
| | | let encoder: ParameterEncoder |
| | | let encoder: any ParameterEncoder |
| | | let headers: HTTPHeaders? |
| | | let requestModifier: RequestModifier? |
| | | |
| | |
| | | /// the provided parameters. `nil` by default. |
| | | /// |
| | | /// - Returns: The created `DataRequest`. |
| | | open func request<Parameters: Encodable>(_ convertible: URLConvertible, |
| | | method: HTTPMethod = .get, |
| | | parameters: Parameters? = nil, |
| | | encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | requestModifier: RequestModifier? = nil) -> DataRequest { |
| | | open func request<Parameters: Encodable & Sendable>(_ convertible: any URLConvertible, |
| | | method: HTTPMethod = .get, |
| | | parameters: Parameters? = nil, |
| | | encoder: any ParameterEncoder = URLEncodedFormParameterEncoder.default, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | requestModifier: RequestModifier? = nil) -> DataRequest { |
| | | let convertible = RequestEncodableConvertible(url: convertible, |
| | | method: method, |
| | | parameters: parameters, |
| | |
| | | /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. |
| | | /// |
| | | /// - Returns: The created `DataRequest`. |
| | | open func request(_ convertible: URLRequestConvertible, interceptor: RequestInterceptor? = nil) -> DataRequest { |
| | | open func request(_ convertible: any URLRequestConvertible, interceptor: (any RequestInterceptor)? = nil) -> DataRequest { |
| | | let request = DataRequest(convertible: convertible, |
| | | underlyingQueue: rootQueue, |
| | | serializationQueue: serializationQueue, |
| | |
| | | /// the provided parameters. `nil` by default. |
| | | /// |
| | | /// - Returns: The created `DataStream` request. |
| | | open func streamRequest<Parameters: Encodable>(_ convertible: URLConvertible, |
| | | method: HTTPMethod = .get, |
| | | parameters: Parameters? = nil, |
| | | encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default, |
| | | headers: HTTPHeaders? = nil, |
| | | automaticallyCancelOnStreamError: Bool = false, |
| | | interceptor: RequestInterceptor? = nil, |
| | | requestModifier: RequestModifier? = nil) -> DataStreamRequest { |
| | | open func streamRequest<Parameters: Encodable & Sendable>(_ convertible: any URLConvertible, |
| | | method: HTTPMethod = .get, |
| | | parameters: Parameters? = nil, |
| | | encoder: any ParameterEncoder = URLEncodedFormParameterEncoder.default, |
| | | headers: HTTPHeaders? = nil, |
| | | automaticallyCancelOnStreamError: Bool = false, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | requestModifier: RequestModifier? = nil) -> DataStreamRequest { |
| | | let convertible = RequestEncodableConvertible(url: convertible, |
| | | method: method, |
| | | parameters: parameters, |
| | |
| | | /// the provided parameters. `nil` by default. |
| | | /// |
| | | /// - Returns: The created `DataStream` request. |
| | | open func streamRequest(_ convertible: URLConvertible, |
| | | open func streamRequest(_ convertible: any URLConvertible, |
| | | method: HTTPMethod = .get, |
| | | headers: HTTPHeaders? = nil, |
| | | automaticallyCancelOnStreamError: Bool = false, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | requestModifier: RequestModifier? = nil) -> DataStreamRequest { |
| | | let convertible = RequestEncodableConvertible(url: convertible, |
| | | method: method, |
| | |
| | | /// by default. |
| | | /// |
| | | /// - Returns: The created `DataStreamRequest`. |
| | | open func streamRequest(_ convertible: URLRequestConvertible, |
| | | open func streamRequest(_ convertible: any URLRequestConvertible, |
| | | automaticallyCancelOnStreamError: Bool = false, |
| | | interceptor: RequestInterceptor? = nil) -> DataStreamRequest { |
| | | interceptor: (any RequestInterceptor)? = nil) -> DataStreamRequest { |
| | | let request = DataStreamRequest(convertible: convertible, |
| | | automaticallyCancelOnStreamError: automaticallyCancelOnStreamError, |
| | | underlyingQueue: rootQueue, |
| | |
| | | #if canImport(Darwin) && !canImport(FoundationNetworking) // Only Apple platforms support URLSessionWebSocketTask. |
| | | @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) |
| | | @_spi(WebSocket) open func webSocketRequest( |
| | | to url: URLConvertible, |
| | | to url: any URLConvertible, |
| | | configuration: WebSocketRequest.Configuration = .default, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | requestModifier: RequestModifier? = nil |
| | | ) -> WebSocketRequest { |
| | | webSocketRequest( |
| | |
| | | |
| | | @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) |
| | | @_spi(WebSocket) open func webSocketRequest<Parameters>( |
| | | to url: URLConvertible, |
| | | to url: any URLConvertible, |
| | | configuration: WebSocketRequest.Configuration = .default, |
| | | parameters: Parameters? = nil, |
| | | encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default, |
| | | encoder: any ParameterEncoder = URLEncodedFormParameterEncoder.default, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | requestModifier: RequestModifier? = nil |
| | | ) -> WebSocketRequest where Parameters: Encodable { |
| | | ) -> WebSocketRequest where Parameters: Encodable & Sendable { |
| | | let convertible = RequestEncodableConvertible(url: url, |
| | | method: .get, |
| | | parameters: parameters, |
| | |
| | | } |
| | | |
| | | @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) |
| | | @_spi(WebSocket) open func webSocketRequest(performing convertible: URLRequestConvertible, |
| | | @_spi(WebSocket) open func webSocketRequest(performing convertible: any URLRequestConvertible, |
| | | configuration: WebSocketRequest.Configuration = .default, |
| | | interceptor: RequestInterceptor? = nil) -> WebSocketRequest { |
| | | interceptor: (any RequestInterceptor)? = nil) -> WebSocketRequest { |
| | | let request = WebSocketRequest(convertible: convertible, |
| | | configuration: configuration, |
| | | underlyingQueue: rootQueue, |
| | |
| | | /// should be moved. `nil` by default. |
| | | /// |
| | | /// - Returns: The created `DownloadRequest`. |
| | | open func download(_ convertible: URLConvertible, |
| | | open func download(_ convertible: any URLConvertible, |
| | | method: HTTPMethod = .get, |
| | | parameters: Parameters? = nil, |
| | | encoding: ParameterEncoding = URLEncoding.default, |
| | | encoding: any ParameterEncoding = URLEncoding.default, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | requestModifier: RequestModifier? = nil, |
| | | to destination: DownloadRequest.Destination? = nil) -> DownloadRequest { |
| | | let convertible = RequestConvertible(url: convertible, |
| | |
| | | /// should be moved. `nil` by default. |
| | | /// |
| | | /// - Returns: The created `DownloadRequest`. |
| | | open func download<Parameters: Encodable>(_ convertible: URLConvertible, |
| | | method: HTTPMethod = .get, |
| | | parameters: Parameters? = nil, |
| | | encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | requestModifier: RequestModifier? = nil, |
| | | to destination: DownloadRequest.Destination? = nil) -> DownloadRequest { |
| | | open func download<Parameters: Encodable & Sendable>(_ convertible: any URLConvertible, |
| | | method: HTTPMethod = .get, |
| | | parameters: Parameters? = nil, |
| | | encoder: any ParameterEncoder = URLEncodedFormParameterEncoder.default, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | requestModifier: RequestModifier? = nil, |
| | | to destination: DownloadRequest.Destination? = nil) -> DownloadRequest { |
| | | let convertible = RequestEncodableConvertible(url: convertible, |
| | | method: method, |
| | | parameters: parameters, |
| | |
| | | /// should be moved. `nil` by default. |
| | | /// |
| | | /// - Returns: The created `DownloadRequest`. |
| | | open func download(_ convertible: URLRequestConvertible, |
| | | interceptor: RequestInterceptor? = nil, |
| | | open func download(_ convertible: any URLRequestConvertible, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | to destination: DownloadRequest.Destination? = nil) -> DownloadRequest { |
| | | let request = DownloadRequest(downloadable: .request(convertible), |
| | | underlyingQueue: rootQueue, |
| | |
| | | /// |
| | | /// - Returns: The created `DownloadRequest`. |
| | | open func download(resumingWith data: Data, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | to destination: DownloadRequest.Destination? = nil) -> DownloadRequest { |
| | | let request = DownloadRequest(downloadable: .resumeData(data), |
| | | underlyingQueue: rootQueue, |
| | |
| | | // MARK: - UploadRequest |
| | | |
| | | struct ParameterlessRequestConvertible: URLRequestConvertible { |
| | | let url: URLConvertible |
| | | let url: any URLConvertible |
| | | let method: HTTPMethod |
| | | let headers: HTTPHeaders? |
| | | let requestModifier: RequestModifier? |
| | |
| | | } |
| | | |
| | | struct Upload: UploadConvertible { |
| | | let request: URLRequestConvertible |
| | | let uploadable: UploadableConvertible |
| | | let request: any URLRequestConvertible |
| | | let uploadable: any UploadableConvertible |
| | | |
| | | func createUploadable() throws -> UploadRequest.Uploadable { |
| | | try uploadable.createUploadable() |
| | |
| | | /// |
| | | /// - Returns: The created `UploadRequest`. |
| | | open func upload(_ data: Data, |
| | | to convertible: URLConvertible, |
| | | to convertible: any URLConvertible, |
| | | method: HTTPMethod = .post, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | fileManager: FileManager = .default, |
| | | requestModifier: RequestModifier? = nil) -> UploadRequest { |
| | | let convertible = ParameterlessRequestConvertible(url: convertible, |
| | |
| | | /// |
| | | /// - Returns: The created `UploadRequest`. |
| | | open func upload(_ data: Data, |
| | | with convertible: URLRequestConvertible, |
| | | interceptor: RequestInterceptor? = nil, |
| | | with convertible: any URLRequestConvertible, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | fileManager: FileManager = .default) -> UploadRequest { |
| | | upload(.data(data), with: convertible, interceptor: interceptor, fileManager: fileManager) |
| | | } |
| | |
| | | /// |
| | | /// - Returns: The created `UploadRequest`. |
| | | open func upload(_ fileURL: URL, |
| | | to convertible: URLConvertible, |
| | | to convertible: any URLConvertible, |
| | | method: HTTPMethod = .post, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | fileManager: FileManager = .default, |
| | | requestModifier: RequestModifier? = nil) -> UploadRequest { |
| | | let convertible = ParameterlessRequestConvertible(url: convertible, |
| | |
| | | /// |
| | | /// - Returns: The created `UploadRequest`. |
| | | open func upload(_ fileURL: URL, |
| | | with convertible: URLRequestConvertible, |
| | | interceptor: RequestInterceptor? = nil, |
| | | with convertible: any URLRequestConvertible, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | fileManager: FileManager = .default) -> UploadRequest { |
| | | upload(.file(fileURL, shouldRemove: false), with: convertible, interceptor: interceptor, fileManager: fileManager) |
| | | } |
| | |
| | | /// |
| | | /// - Returns: The created `UploadRequest`. |
| | | open func upload(_ stream: InputStream, |
| | | to convertible: URLConvertible, |
| | | to convertible: any URLConvertible, |
| | | method: HTTPMethod = .post, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | fileManager: FileManager = .default, |
| | | requestModifier: RequestModifier? = nil) -> UploadRequest { |
| | | let convertible = ParameterlessRequestConvertible(url: convertible, |
| | |
| | | /// |
| | | /// - Returns: The created `UploadRequest`. |
| | | open func upload(_ stream: InputStream, |
| | | with convertible: URLRequestConvertible, |
| | | interceptor: RequestInterceptor? = nil, |
| | | with convertible: any URLRequestConvertible, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | fileManager: FileManager = .default) -> UploadRequest { |
| | | upload(.stream(stream), with: convertible, interceptor: interceptor, fileManager: fileManager) |
| | | } |
| | |
| | | /// |
| | | /// - Returns: The created `UploadRequest`. |
| | | open func upload(multipartFormData: @escaping (MultipartFormData) -> Void, |
| | | to url: URLConvertible, |
| | | to url: any URLConvertible, |
| | | usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold, |
| | | method: HTTPMethod = .post, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | fileManager: FileManager = .default, |
| | | requestModifier: RequestModifier? = nil) -> UploadRequest { |
| | | let convertible = ParameterlessRequestConvertible(url: url, |
| | |
| | | /// |
| | | /// - Returns: The created `UploadRequest`. |
| | | open func upload(multipartFormData: @escaping (MultipartFormData) -> Void, |
| | | with request: URLRequestConvertible, |
| | | with request: any URLRequestConvertible, |
| | | usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | fileManager: FileManager = .default) -> UploadRequest { |
| | | let formData = MultipartFormData(fileManager: fileManager) |
| | | multipartFormData(formData) |
| | |
| | | /// |
| | | /// - Returns: The created `UploadRequest`. |
| | | open func upload(multipartFormData: MultipartFormData, |
| | | to url: URLConvertible, |
| | | to url: any URLConvertible, |
| | | usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold, |
| | | method: HTTPMethod = .post, |
| | | headers: HTTPHeaders? = nil, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | fileManager: FileManager = .default, |
| | | requestModifier: RequestModifier? = nil) -> UploadRequest { |
| | | let convertible = ParameterlessRequestConvertible(url: url, |
| | |
| | | /// |
| | | /// - Returns: The created `UploadRequest`. |
| | | open func upload(multipartFormData: MultipartFormData, |
| | | with request: URLRequestConvertible, |
| | | with request: any URLRequestConvertible, |
| | | usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold, |
| | | interceptor: RequestInterceptor? = nil, |
| | | interceptor: (any RequestInterceptor)? = nil, |
| | | fileManager: FileManager = .default) -> UploadRequest { |
| | | let multipartUpload = MultipartUpload(encodingMemoryThreshold: encodingMemoryThreshold, |
| | | request: request, |
| | |
| | | // MARK: Uploadable |
| | | |
| | | func upload(_ uploadable: UploadRequest.Uploadable, |
| | | with convertible: URLRequestConvertible, |
| | | interceptor: RequestInterceptor?, |
| | | with convertible: any URLRequestConvertible, |
| | | interceptor: (any RequestInterceptor)?, |
| | | fileManager: FileManager) -> UploadRequest { |
| | | let uploadable = Upload(request: convertible, uploadable: uploadable) |
| | | |
| | | return upload(uploadable, interceptor: interceptor, fileManager: fileManager) |
| | | } |
| | | |
| | | func upload(_ upload: UploadConvertible, interceptor: RequestInterceptor?, fileManager: FileManager) -> UploadRequest { |
| | | func upload(_ upload: any UploadConvertible, interceptor: (any RequestInterceptor)?, fileManager: FileManager) -> UploadRequest { |
| | | let request = UploadRequest(convertible: upload, |
| | | underlyingQueue: rootQueue, |
| | | serializationQueue: serializationQueue, |
| | |
| | | } |
| | | |
| | | func performSetupOperations(for request: Request, |
| | | convertible: URLRequestConvertible, |
| | | shouldCreateTask: @escaping () -> Bool = { true }) { |
| | | convertible: any URLRequestConvertible, |
| | | shouldCreateTask: @escaping @Sendable () -> Bool = { true }) { |
| | | dispatchPrecondition(condition: .onQueue(requestQueue)) |
| | | |
| | | let initialRequest: URLRequest |
| | |
| | | |
| | | // MARK: - Adapters and Retriers |
| | | |
| | | func adapter(for request: Request) -> RequestAdapter? { |
| | | func adapter(for request: Request) -> (any RequestAdapter)? { |
| | | if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor { |
| | | return Interceptor(adapters: [requestInterceptor, sessionInterceptor]) |
| | | Interceptor(adapters: [requestInterceptor, sessionInterceptor]) |
| | | } else { |
| | | return request.interceptor ?? interceptor |
| | | request.interceptor ?? interceptor |
| | | } |
| | | } |
| | | |
| | | func retrier(for request: Request) -> RequestRetrier? { |
| | | func retrier(for request: Request) -> (any RequestRetrier)? { |
| | | if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor { |
| | | return Interceptor(retriers: [requestInterceptor, sessionInterceptor]) |
| | | Interceptor(retriers: [requestInterceptor, sessionInterceptor]) |
| | | } else { |
| | | return request.interceptor ?? interceptor |
| | | request.interceptor ?? interceptor |
| | | } |
| | | } |
| | | |
| | |
| | | activeRequests.remove(request) |
| | | } |
| | | |
| | | public func retryResult(for request: Request, dueTo error: AFError, completion: @escaping (RetryResult) -> Void) { |
| | | public func retryResult(for request: Request, dueTo error: AFError, completion: @escaping @Sendable (RetryResult) -> Void) { |
| | | guard let retrier = retrier(for: request) else { |
| | | rootQueue.async { completion(.doNotRetry) } |
| | | return |
| | |
| | | |
| | | public func retryRequest(_ request: Request, withDelay timeDelay: TimeInterval?) { |
| | | rootQueue.async { |
| | | let retry: () -> Void = { |
| | | let retry: @Sendable () -> Void = { |
| | | guard !request.isCancelled else { return } |
| | | |
| | | request.prepareForRetry() |
| | |
| | | session.configuration.urlCredentialStorage?.defaultCredential(for: protectionSpace) |
| | | } |
| | | |
| | | func cancelRequestsForSessionInvalidation(with error: Error?) { |
| | | func cancelRequestsForSessionInvalidation(with error: (any Error)?) { |
| | | dispatchPrecondition(condition: .onQueue(rootQueue)) |
| | | |
| | | requestTaskMap.requests.forEach { $0.finish(error: AFError.sessionInvalidated(error: error)) } |