Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
//
2
//  Session.swift
3
//
4
//  Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5
//
6
//  Permission is hereby granted, free of charge, to any person obtaining a copy
7
//  of this software and associated documentation files (the "Software"), to deal
8
//  in the Software without restriction, including without limitation the rights
9
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
//  copies of the Software, and to permit persons to whom the Software is
11
//  furnished to do so, subject to the following conditions:
12
//
13
//  The above copyright notice and this permission notice shall be included in
14
//  all copies or substantial portions of the Software.
15
//
16
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
//  THE SOFTWARE.
23
//
24
 
25
import Foundation
26
 
27
/// `Session` creates and manages Alamofire's `Request` types during their lifetimes. It also provides common
28
/// functionality for all `Request`s, including queuing, interception, trust management, redirect handling, and response
29
/// cache handling.
30
open class Session {
31
    /// Shared singleton instance used by all `AF.request` APIs. Cannot be modified.
32
    public static let `default` = Session()
33
 
34
    /// Underlying `URLSession` used to create `URLSessionTasks` for this instance, and for which this instance's
35
    /// `delegate` handles `URLSessionDelegate` callbacks.
36
    ///
37
    /// - Note: This instance should **NOT** be used to interact with the underlying `URLSessionTask`s. Doing so will
38
    ///         break internal Alamofire logic that tracks those tasks.
39
    ///
40
    public let session: URLSession
41
    /// Instance's `SessionDelegate`, which handles the `URLSessionDelegate` methods and `Request` interaction.
42
    public let delegate: SessionDelegate
43
    /// Root `DispatchQueue` for all internal callbacks and state update. **MUST** be a serial queue.
44
    public let rootQueue: DispatchQueue
45
    /// Value determining whether this instance automatically calls `resume()` on all created `Request`s.
46
    public let startRequestsImmediately: Bool
47
    /// `DispatchQueue` on which `URLRequest`s are created asynchronously. By default this queue uses `rootQueue` as its
48
    /// `target`, but a separate queue can be used if request creation is determined to be a bottleneck. Always profile
49
    /// and test before introducing an additional queue.
50
    public let requestQueue: DispatchQueue
51
    /// `DispatchQueue` passed to all `Request`s on which they perform their response serialization. By default this
52
    /// queue uses `rootQueue` as its `target` but a separate queue can be used if response serialization is determined
53
    /// to be a bottleneck. Always profile and test before introducing an additional queue.
54
    public let serializationQueue: DispatchQueue
55
    /// `RequestInterceptor` used for all `Request` created by the instance. `RequestInterceptor`s can also be set on a
56
    /// per-`Request` basis, in which case the `Request`'s interceptor takes precedence over this value.
57
    public let interceptor: RequestInterceptor?
58
    /// `ServerTrustManager` instance used to evaluate all trust challenges and provide certificate and key pinning.
59
    public let serverTrustManager: ServerTrustManager?
60
    /// `RedirectHandler` instance used to provide customization for request redirection.
61
    public let redirectHandler: RedirectHandler?
62
    /// `CachedResponseHandler` instance used to provide customization of cached response handling.
63
    public let cachedResponseHandler: CachedResponseHandler?
64
    /// `CompositeEventMonitor` used to compose Alamofire's `defaultEventMonitors` and any passed `EventMonitor`s.
65
    public let eventMonitor: CompositeEventMonitor
66
    /// `EventMonitor`s included in all instances. `[AlamofireNotifications()]` by default.
67
    public let defaultEventMonitors: [EventMonitor] = [AlamofireNotifications()]
68
 
69
    /// Internal map between `Request`s and any `URLSessionTasks` that may be in flight for them.
70
    var requestTaskMap = RequestTaskMap()
71
    /// `Set` of currently active `Request`s.
72
    var activeRequests: Set<Request> = []
73
    /// Completion events awaiting `URLSessionTaskMetrics`.
74
    var waitingCompletions: [URLSessionTask: () -> Void] = [:]
75
 
76
    /// Creates a `Session` from a `URLSession` and other parameters.
77
    ///
78
    /// - Note: When passing a `URLSession`, you must create the `URLSession` with a specific `delegateQueue` value and
79
    ///         pass the `delegateQueue`'s `underlyingQueue` as the `rootQueue` parameter of this initializer.
80
    ///
81
    /// - Parameters:
82
    ///   - session:                  Underlying `URLSession` for this instance.
83
    ///   - delegate:                 `SessionDelegate` that handles `session`'s delegate callbacks as well as `Request`
84
    ///                               interaction.
85
    ///   - rootQueue:                Root `DispatchQueue` for all internal callbacks and state updates. **MUST** be a
86
    ///                               serial queue.
87
    ///   - startRequestsImmediately: Determines whether this instance will automatically start all `Request`s. `true`
88
    ///                               by default. If set to `false`, all `Request`s created must have `.resume()` called.
89
    ///                               on them for them to start.
90
    ///   - requestQueue:             `DispatchQueue` on which to perform `URLRequest` creation. By default this queue
91
    ///                               will use the `rootQueue` as its `target`. A separate queue can be used if it's
92
    ///                               determined request creation is a bottleneck, but that should only be done after
93
    ///                               careful testing and profiling. `nil` by default.
94
    ///   - serializationQueue:       `DispatchQueue` on which to perform all response serialization. By default this
95
    ///                               queue will use the `rootQueue` as its `target`. A separate queue can be used if
96
    ///                               it's determined response serialization is a bottleneck, but that should only be
97
    ///                               done after careful testing and profiling. `nil` by default.
98
    ///   - interceptor:              `RequestInterceptor` to be used for all `Request`s created by this instance. `nil`
99
    ///                               by default.
100
    ///   - serverTrustManager:       `ServerTrustManager` to be used for all trust evaluations by this instance. `nil`
101
    ///                               by default.
102
    ///   - redirectHandler:          `RedirectHandler` to be used by all `Request`s created by this instance. `nil` by
103
    ///                               default.
104
    ///   - cachedResponseHandler:    `CachedResponseHandler` to be used by all `Request`s created by this instance.
105
    ///                               `nil` by default.
106
    ///   - eventMonitors:            Additional `EventMonitor`s used by the instance. Alamofire always adds a
107
    ///                               `AlamofireNotifications` `EventMonitor` to the array passed here. `[]` by default.
108
    public init(session: URLSession,
109
                delegate: SessionDelegate,
110
                rootQueue: DispatchQueue,
111
                startRequestsImmediately: Bool = true,
112
                requestQueue: DispatchQueue? = nil,
113
                serializationQueue: DispatchQueue? = nil,
114
                interceptor: RequestInterceptor? = nil,
115
                serverTrustManager: ServerTrustManager? = nil,
116
                redirectHandler: RedirectHandler? = nil,
117
                cachedResponseHandler: CachedResponseHandler? = nil,
118
                eventMonitors: [EventMonitor] = []) {
119
        precondition(session.configuration.identifier == nil,
120
                     "Alamofire does not support background URLSessionConfigurations.")
121
        precondition(session.delegateQueue.underlyingQueue === rootQueue,
122
                     "Session(session:) initializer must be passed the DispatchQueue used as the delegateQueue's underlyingQueue as rootQueue.")
123
 
124
        self.session = session
125
        self.delegate = delegate
126
        self.rootQueue = rootQueue
127
        self.startRequestsImmediately = startRequestsImmediately
128
        self.requestQueue = requestQueue ?? DispatchQueue(label: "\(rootQueue.label).requestQueue", target: rootQueue)
129
        self.serializationQueue = serializationQueue ?? DispatchQueue(label: "\(rootQueue.label).serializationQueue", target: rootQueue)
130
        self.interceptor = interceptor
131
        self.serverTrustManager = serverTrustManager
132
        self.redirectHandler = redirectHandler
133
        self.cachedResponseHandler = cachedResponseHandler
134
        eventMonitor = CompositeEventMonitor(monitors: defaultEventMonitors + eventMonitors)
135
        delegate.eventMonitor = eventMonitor
136
        delegate.stateProvider = self
137
    }
138
 
139
    /// Creates a `Session` from a `URLSessionConfiguration`.
140
    ///
141
    /// - Note: This initializer lets Alamofire handle the creation of the underlying `URLSession` and its
142
    ///         `delegateQueue`, and is the recommended initializer for most uses.
143
    ///
144
    /// - Parameters:
145
    ///   - configuration:            `URLSessionConfiguration` to be used to create the underlying `URLSession`. Changes
146
    ///                               to this value after being passed to this initializer will have no effect.
147
    ///                               `URLSessionConfiguration.af.default` by default.
148
    ///   - delegate:                 `SessionDelegate` that handles `session`'s delegate callbacks as well as `Request`
149
    ///                               interaction. `SessionDelegate()` by default.
150
    ///   - rootQueue:                Root `DispatchQueue` for all internal callbacks and state updates. **MUST** be a
151
    ///                               serial queue. `DispatchQueue(label: "org.alamofire.session.rootQueue")` by default.
152
    ///   - startRequestsImmediately: Determines whether this instance will automatically start all `Request`s. `true`
153
    ///                               by default. If set to `false`, all `Request`s created must have `.resume()` called.
154
    ///                               on them for them to start.
155
    ///   - requestQueue:             `DispatchQueue` on which to perform `URLRequest` creation. By default this queue
156
    ///                               will use the `rootQueue` as its `target`. A separate queue can be used if it's
157
    ///                               determined request creation is a bottleneck, but that should only be done after
158
    ///                               careful testing and profiling. `nil` by default.
159
    ///   - serializationQueue:       `DispatchQueue` on which to perform all response serialization. By default this
160
    ///                               queue will use the `rootQueue` as its `target`. A separate queue can be used if
161
    ///                               it's determined response serialization is a bottleneck, but that should only be
162
    ///                               done after careful testing and profiling. `nil` by default.
163
    ///   - interceptor:              `RequestInterceptor` to be used for all `Request`s created by this instance. `nil`
164
    ///                               by default.
165
    ///   - serverTrustManager:       `ServerTrustManager` to be used for all trust evaluations by this instance. `nil`
166
    ///                               by default.
167
    ///   - redirectHandler:          `RedirectHandler` to be used by all `Request`s created by this instance. `nil` by
168
    ///                               default.
169
    ///   - cachedResponseHandler:    `CachedResponseHandler` to be used by all `Request`s created by this instance.
170
    ///                               `nil` by default.
171
    ///   - eventMonitors:            Additional `EventMonitor`s used by the instance. Alamofire always adds a
172
    ///                               `AlamofireNotifications` `EventMonitor` to the array passed here. `[]` by default.
173
    public convenience init(configuration: URLSessionConfiguration = URLSessionConfiguration.af.default,
174
                            delegate: SessionDelegate = SessionDelegate(),
175
                            rootQueue: DispatchQueue = DispatchQueue(label: "org.alamofire.session.rootQueue"),
176
                            startRequestsImmediately: Bool = true,
177
                            requestQueue: DispatchQueue? = nil,
178
                            serializationQueue: DispatchQueue? = nil,
179
                            interceptor: RequestInterceptor? = nil,
180
                            serverTrustManager: ServerTrustManager? = nil,
181
                            redirectHandler: RedirectHandler? = nil,
182
                            cachedResponseHandler: CachedResponseHandler? = nil,
183
                            eventMonitors: [EventMonitor] = []) {
184
        precondition(configuration.identifier == nil, "Alamofire does not support background URLSessionConfigurations.")
185
 
186
        // Retarget the incoming rootQueue for safety, unless it's the main queue, which we know is safe.
187
        let serialRootQueue = (rootQueue === DispatchQueue.main) ? rootQueue : DispatchQueue(label: rootQueue.label,
188
                                                                                             target: rootQueue)
189
        let delegateQueue = OperationQueue(maxConcurrentOperationCount: 1, underlyingQueue: serialRootQueue, name: "\(serialRootQueue.label).sessionDelegate")
190
        let session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: delegateQueue)
191
 
192
        self.init(session: session,
193
                  delegate: delegate,
194
                  rootQueue: serialRootQueue,
195
                  startRequestsImmediately: startRequestsImmediately,
196
                  requestQueue: requestQueue,
197
                  serializationQueue: serializationQueue,
198
                  interceptor: interceptor,
199
                  serverTrustManager: serverTrustManager,
200
                  redirectHandler: redirectHandler,
201
                  cachedResponseHandler: cachedResponseHandler,
202
                  eventMonitors: eventMonitors)
203
    }
204
 
205
    deinit {
206
        finishRequestsForDeinit()
207
        session.invalidateAndCancel()
208
    }
209
 
210
    // MARK: - All Requests API
211
 
212
    /// Perform an action on all active `Request`s.
213
    ///
214
    /// - Note: The provided `action` closure is performed asynchronously, meaning that some `Request`s may complete and
215
    ///         be unavailable by time it runs. Additionally, this action is performed on the instances's `rootQueue`,
216
    ///         so care should be taken that actions are fast. Once the work on the `Request`s is complete, any
217
    ///         additional work should be performed on another queue.
218
    ///
219
    /// - Parameters:
220
    ///   - action:     Closure to perform with all `Request`s.
221
    public func withAllRequests(perform action: @escaping (Set<Request>) -> Void) {
222
        rootQueue.async {
223
            action(self.activeRequests)
224
        }
225
    }
226
 
227
    /// Cancel all active `Request`s, optionally calling a completion handler when complete.
228
    ///
229
    /// - Note: This is an asynchronous operation and does not block the creation of future `Request`s. Cancelled
230
    ///         `Request`s may not cancel immediately due internal work, and may not cancel at all if they are close to
231
    ///         completion when cancelled.
232
    ///
233
    /// - Parameters:
234
    ///   - queue:      `DispatchQueue` on which the completion handler is run. `.main` by default.
235
    ///   - completion: Closure to be called when all `Request`s have been cancelled.
236
    public func cancelAllRequests(completingOnQueue queue: DispatchQueue = .main, completion: (() -> Void)? = nil) {
237
        withAllRequests { requests in
238
            requests.forEach { $0.cancel() }
239
            queue.async {
240
                completion?()
241
            }
242
        }
243
    }
244
 
245
    // MARK: - DataRequest
246
 
247
    /// Closure which provides a `URLRequest` for mutation.
248
    public typealias RequestModifier = (inout URLRequest) throws -> Void
249
 
250
    struct RequestConvertible: URLRequestConvertible {
251
        let url: URLConvertible
252
        let method: HTTPMethod
253
        let parameters: Parameters?
254
        let encoding: ParameterEncoding
255
        let headers: HTTPHeaders?
256
        let requestModifier: RequestModifier?
257
 
258
        func asURLRequest() throws -> URLRequest {
259
            var request = try URLRequest(url: url, method: method, headers: headers)
260
            try requestModifier?(&request)
261
 
262
            return try encoding.encode(request, with: parameters)
263
        }
264
    }
265
 
266
    /// Creates a `DataRequest` from a `URLRequest` created using the passed components and a `RequestInterceptor`.
267
    ///
268
    /// - Parameters:
269
    ///   - convertible:     `URLConvertible` value to be used as the `URLRequest`'s `URL`.
270
    ///   - method:          `HTTPMethod` for the `URLRequest`. `.get` by default.
271
    ///   - parameters:      `Parameters` (a.k.a. `[String: Any]`) value to be encoded into the `URLRequest`. `nil` by
272
    ///                      default.
273
    ///   - encoding:        `ParameterEncoding` to be used to encode the `parameters` value into the `URLRequest`.
274
    ///                      `URLEncoding.default` by default.
275
    ///   - headers:         `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
276
    ///   - interceptor:     `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
277
    ///   - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided
278
    ///                      parameters. `nil` by default.
279
    ///
280
    /// - Returns:       The created `DataRequest`.
281
    open func request(_ convertible: URLConvertible,
282
                      method: HTTPMethod = .get,
283
                      parameters: Parameters? = nil,
284
                      encoding: ParameterEncoding = URLEncoding.default,
285
                      headers: HTTPHeaders? = nil,
286
                      interceptor: RequestInterceptor? = nil,
287
                      requestModifier: RequestModifier? = nil) -> DataRequest {
288
        let convertible = RequestConvertible(url: convertible,
289
                                             method: method,
290
                                             parameters: parameters,
291
                                             encoding: encoding,
292
                                             headers: headers,
293
                                             requestModifier: requestModifier)
294
 
295
        return request(convertible, interceptor: interceptor)
296
    }
297
 
298
    struct RequestEncodableConvertible<Parameters: Encodable>: URLRequestConvertible {
299
        let url: URLConvertible
300
        let method: HTTPMethod
301
        let parameters: Parameters?
302
        let encoder: ParameterEncoder
303
        let headers: HTTPHeaders?
304
        let requestModifier: RequestModifier?
305
 
306
        func asURLRequest() throws -> URLRequest {
307
            var request = try URLRequest(url: url, method: method, headers: headers)
308
            try requestModifier?(&request)
309
 
310
            return try parameters.map { try encoder.encode($0, into: request) } ?? request
311
        }
312
    }
313
 
314
    /// Creates a `DataRequest` from a `URLRequest` created using the passed components, `Encodable` parameters, and a
315
    /// `RequestInterceptor`.
316
    ///
317
    /// - Parameters:
318
    ///   - convertible:     `URLConvertible` value to be used as the `URLRequest`'s `URL`.
319
    ///   - method:          `HTTPMethod` for the `URLRequest`. `.get` by default.
320
    ///   - parameters:      `Encodable` value to be encoded into the `URLRequest`. `nil` by default.
321
    ///   - encoder:         `ParameterEncoder` to be used to encode the `parameters` value into the `URLRequest`.
322
    ///                      `URLEncodedFormParameterEncoder.default` by default.
323
    ///   - headers:         `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
324
    ///   - interceptor:     `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
325
    ///   - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from
326
    ///                      the provided parameters. `nil` by default.
327
    ///
328
    /// - Returns:           The created `DataRequest`.
329
    open func request<Parameters: Encodable>(_ convertible: URLConvertible,
330
                                             method: HTTPMethod = .get,
331
                                             parameters: Parameters? = nil,
332
                                             encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default,
333
                                             headers: HTTPHeaders? = nil,
334
                                             interceptor: RequestInterceptor? = nil,
335
                                             requestModifier: RequestModifier? = nil) -> DataRequest {
336
        let convertible = RequestEncodableConvertible(url: convertible,
337
                                                      method: method,
338
                                                      parameters: parameters,
339
                                                      encoder: encoder,
340
                                                      headers: headers,
341
                                                      requestModifier: requestModifier)
342
 
343
        return request(convertible, interceptor: interceptor)
344
    }
345
 
346
    /// Creates a `DataRequest` from a `URLRequestConvertible` value and a `RequestInterceptor`.
347
    ///
348
    /// - Parameters:
349
    ///   - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`.
350
    ///   - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
351
    ///
352
    /// - Returns:       The created `DataRequest`.
353
    open func request(_ convertible: URLRequestConvertible, interceptor: RequestInterceptor? = nil) -> DataRequest {
354
        let request = DataRequest(convertible: convertible,
355
                                  underlyingQueue: rootQueue,
356
                                  serializationQueue: serializationQueue,
357
                                  eventMonitor: eventMonitor,
358
                                  interceptor: interceptor,
359
                                  delegate: self)
360
 
361
        perform(request)
362
 
363
        return request
364
    }
365
 
366
    // MARK: - DataStreamRequest
367
 
368
    /// Creates a `DataStreamRequest` from the passed components, `Encodable` parameters, and `RequestInterceptor`.
369
    ///
370
    /// - Parameters:
371
    ///   - convertible:                      `URLConvertible` value to be used as the `URLRequest`'s `URL`.
372
    ///   - method:                           `HTTPMethod` for the `URLRequest`. `.get` by default.
373
    ///   - parameters:                       `Encodable` value to be encoded into the `URLRequest`. `nil` by default.
374
    ///   - encoder:                          `ParameterEncoder` to be used to encode the `parameters` value into the
375
    ///                                       `URLRequest`.
376
    ///                                       `URLEncodedFormParameterEncoder.default` by default.
377
    ///   - headers:                          `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
378
    ///   - automaticallyCancelOnStreamError: `Bool` indicating whether the instance should be canceled when an `Error`
379
    ///                                       is thrown while serializing stream `Data`. `false` by default.
380
    ///   - interceptor:                      `RequestInterceptor` value to be used by the returned `DataRequest`. `nil`
381
    ///                                       by default.
382
    ///   - requestModifier:                  `RequestModifier` which will be applied to the `URLRequest` created from
383
    ///                                       the provided parameters. `nil` by default.
384
    ///
385
    /// - Returns:       The created `DataStream` request.
386
    open func streamRequest<Parameters: Encodable>(_ convertible: URLConvertible,
387
                                                   method: HTTPMethod = .get,
388
                                                   parameters: Parameters? = nil,
389
                                                   encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default,
390
                                                   headers: HTTPHeaders? = nil,
391
                                                   automaticallyCancelOnStreamError: Bool = false,
392
                                                   interceptor: RequestInterceptor? = nil,
393
                                                   requestModifier: RequestModifier? = nil) -> DataStreamRequest {
394
        let convertible = RequestEncodableConvertible(url: convertible,
395
                                                      method: method,
396
                                                      parameters: parameters,
397
                                                      encoder: encoder,
398
                                                      headers: headers,
399
                                                      requestModifier: requestModifier)
400
 
401
        return streamRequest(convertible,
402
                             automaticallyCancelOnStreamError: automaticallyCancelOnStreamError,
403
                             interceptor: interceptor)
404
    }
405
 
406
    /// Creates a `DataStreamRequest` from the passed components and `RequestInterceptor`.
407
    ///
408
    /// - Parameters:
409
    ///   - convertible:                      `URLConvertible` value to be used as the `URLRequest`'s `URL`.
410
    ///   - method:                           `HTTPMethod` for the `URLRequest`. `.get` by default.
411
    ///   - headers:                          `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
412
    ///   - automaticallyCancelOnStreamError: `Bool` indicating whether the instance should be canceled when an `Error`
413
    ///                                       is thrown while serializing stream `Data`. `false` by default.
414
    ///   - interceptor:                      `RequestInterceptor` value to be used by the returned `DataRequest`. `nil`
415
    ///                                       by default.
416
    ///   - requestModifier:                  `RequestModifier` which will be applied to the `URLRequest` created from
417
    ///                                       the provided parameters. `nil` by default.
418
    ///
419
    /// - Returns:       The created `DataStream` request.
420
    open func streamRequest(_ convertible: URLConvertible,
421
                            method: HTTPMethod = .get,
422
                            headers: HTTPHeaders? = nil,
423
                            automaticallyCancelOnStreamError: Bool = false,
424
                            interceptor: RequestInterceptor? = nil,
425
                            requestModifier: RequestModifier? = nil) -> DataStreamRequest {
426
        let convertible = RequestEncodableConvertible(url: convertible,
427
                                                      method: method,
428
                                                      parameters: Empty?.none,
429
                                                      encoder: URLEncodedFormParameterEncoder.default,
430
                                                      headers: headers,
431
                                                      requestModifier: requestModifier)
432
 
433
        return streamRequest(convertible,
434
                             automaticallyCancelOnStreamError: automaticallyCancelOnStreamError,
435
                             interceptor: interceptor)
436
    }
437
 
438
    /// Creates a `DataStreamRequest` from the passed `URLRequestConvertible` value and `RequestInterceptor`.
439
    ///
440
    /// - Parameters:
441
    ///   - convertible:                      `URLRequestConvertible` value to be used to create the `URLRequest`.
442
    ///   - automaticallyCancelOnStreamError: `Bool` indicating whether the instance should be canceled when an `Error`
443
    ///                                       is thrown while serializing stream `Data`. `false` by default.
444
    ///   - interceptor:                      `RequestInterceptor` value to be used by the returned `DataRequest`. `nil`
445
    ///                                        by default.
446
    ///
447
    /// - Returns:       The created `DataStreamRequest`.
448
    open func streamRequest(_ convertible: URLRequestConvertible,
449
                            automaticallyCancelOnStreamError: Bool = false,
450
                            interceptor: RequestInterceptor? = nil) -> DataStreamRequest {
451
        let request = DataStreamRequest(convertible: convertible,
452
                                        automaticallyCancelOnStreamError: automaticallyCancelOnStreamError,
453
                                        underlyingQueue: rootQueue,
454
                                        serializationQueue: serializationQueue,
455
                                        eventMonitor: eventMonitor,
456
                                        interceptor: interceptor,
457
                                        delegate: self)
458
 
459
        perform(request)
460
 
461
        return request
462
    }
463
 
464
    // MARK: - DownloadRequest
465
 
466
    /// Creates a `DownloadRequest` using a `URLRequest` created using the passed components, `RequestInterceptor`, and
467
    /// `Destination`.
468
    ///
469
    /// - Parameters:
470
    ///   - convertible:     `URLConvertible` value to be used as the `URLRequest`'s `URL`.
471
    ///   - method:          `HTTPMethod` for the `URLRequest`. `.get` by default.
472
    ///   - parameters:      `Parameters` (a.k.a. `[String: Any]`) value to be encoded into the `URLRequest`. `nil` by
473
    ///                      default.
474
    ///   - encoding:        `ParameterEncoding` to be used to encode the `parameters` value into the `URLRequest`.
475
    ///                      Defaults to `URLEncoding.default`.
476
    ///   - headers:         `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
477
    ///   - interceptor:     `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
478
    ///   - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided
479
    ///                      parameters. `nil` by default.
480
    ///   - destination:     `DownloadRequest.Destination` closure used to determine how and where the downloaded file
481
    ///                      should be moved. `nil` by default.
482
    ///
483
    /// - Returns:           The created `DownloadRequest`.
484
    open func download(_ convertible: URLConvertible,
485
                       method: HTTPMethod = .get,
486
                       parameters: Parameters? = nil,
487
                       encoding: ParameterEncoding = URLEncoding.default,
488
                       headers: HTTPHeaders? = nil,
489
                       interceptor: RequestInterceptor? = nil,
490
                       requestModifier: RequestModifier? = nil,
491
                       to destination: DownloadRequest.Destination? = nil) -> DownloadRequest {
492
        let convertible = RequestConvertible(url: convertible,
493
                                             method: method,
494
                                             parameters: parameters,
495
                                             encoding: encoding,
496
                                             headers: headers,
497
                                             requestModifier: requestModifier)
498
 
499
        return download(convertible, interceptor: interceptor, to: destination)
500
    }
501
 
502
    /// Creates a `DownloadRequest` from a `URLRequest` created using the passed components, `Encodable` parameters, and
503
    /// a `RequestInterceptor`.
504
    ///
505
    /// - Parameters:
506
    ///   - convertible:     `URLConvertible` value to be used as the `URLRequest`'s `URL`.
507
    ///   - method:          `HTTPMethod` for the `URLRequest`. `.get` by default.
508
    ///   - parameters:      Value conforming to `Encodable` to be encoded into the `URLRequest`. `nil` by default.
509
    ///   - encoder:         `ParameterEncoder` to be used to encode the `parameters` value into the `URLRequest`.
510
    ///                      Defaults to `URLEncodedFormParameterEncoder.default`.
511
    ///   - headers:         `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
512
    ///   - interceptor:     `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
513
    ///   - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided
514
    ///                      parameters. `nil` by default.
515
    ///   - destination:     `DownloadRequest.Destination` closure used to determine how and where the downloaded file
516
    ///                      should be moved. `nil` by default.
517
    ///
518
    /// - Returns:           The created `DownloadRequest`.
519
    open func download<Parameters: Encodable>(_ convertible: URLConvertible,
520
                                              method: HTTPMethod = .get,
521
                                              parameters: Parameters? = nil,
522
                                              encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default,
523
                                              headers: HTTPHeaders? = nil,
524
                                              interceptor: RequestInterceptor? = nil,
525
                                              requestModifier: RequestModifier? = nil,
526
                                              to destination: DownloadRequest.Destination? = nil) -> DownloadRequest {
527
        let convertible = RequestEncodableConvertible(url: convertible,
528
                                                      method: method,
529
                                                      parameters: parameters,
530
                                                      encoder: encoder,
531
                                                      headers: headers,
532
                                                      requestModifier: requestModifier)
533
 
534
        return download(convertible, interceptor: interceptor, to: destination)
535
    }
536
 
537
    /// Creates a `DownloadRequest` from a `URLRequestConvertible` value, a `RequestInterceptor`, and a `Destination`.
538
    ///
539
    /// - Parameters:
540
    ///   - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`.
541
    ///   - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
542
    ///   - destination: `DownloadRequest.Destination` closure used to determine how and where the downloaded file
543
    ///                  should be moved. `nil` by default.
544
    ///
545
    /// - Returns:       The created `DownloadRequest`.
546
    open func download(_ convertible: URLRequestConvertible,
547
                       interceptor: RequestInterceptor? = nil,
548
                       to destination: DownloadRequest.Destination? = nil) -> DownloadRequest {
549
        let request = DownloadRequest(downloadable: .request(convertible),
550
                                      underlyingQueue: rootQueue,
551
                                      serializationQueue: serializationQueue,
552
                                      eventMonitor: eventMonitor,
553
                                      interceptor: interceptor,
554
                                      delegate: self,
555
                                      destination: destination ?? DownloadRequest.defaultDestination)
556
 
557
        perform(request)
558
 
559
        return request
560
    }
561
 
562
    /// Creates a `DownloadRequest` from the `resumeData` produced from a previously cancelled `DownloadRequest`, as
563
    /// well as a `RequestInterceptor`, and a `Destination`.
564
    ///
565
    /// - Note: If `destination` is not specified, the download will be moved to a temporary location determined by
566
    ///         Alamofire. The file will not be deleted until the system purges the temporary files.
567
    ///
568
    /// - Note: On some versions of all Apple platforms (iOS 10 - 10.2, macOS 10.12 - 10.12.2, tvOS 10 - 10.1, watchOS 3 - 3.1.1),
569
    /// `resumeData` is broken on background URL session configurations. There's an underlying bug in the `resumeData`
570
    /// generation logic where the data is written incorrectly and will always fail to resume the download. For more
571
    /// information about the bug and possible workarounds, please refer to the [this Stack Overflow post](http://stackoverflow.com/a/39347461/1342462).
572
    ///
573
    /// - Parameters:
574
    ///   - data:        The resume data from a previously cancelled `DownloadRequest` or `URLSessionDownloadTask`.
575
    ///   - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
576
    ///   - destination: `DownloadRequest.Destination` closure used to determine how and where the downloaded file
577
    ///                  should be moved. `nil` by default.
578
    ///
579
    /// - Returns:       The created `DownloadRequest`.
580
    open func download(resumingWith data: Data,
581
                       interceptor: RequestInterceptor? = nil,
582
                       to destination: DownloadRequest.Destination? = nil) -> DownloadRequest {
583
        let request = DownloadRequest(downloadable: .resumeData(data),
584
                                      underlyingQueue: rootQueue,
585
                                      serializationQueue: serializationQueue,
586
                                      eventMonitor: eventMonitor,
587
                                      interceptor: interceptor,
588
                                      delegate: self,
589
                                      destination: destination ?? DownloadRequest.defaultDestination)
590
 
591
        perform(request)
592
 
593
        return request
594
    }
595
 
596
    // MARK: - UploadRequest
597
 
598
    struct ParameterlessRequestConvertible: URLRequestConvertible {
599
        let url: URLConvertible
600
        let method: HTTPMethod
601
        let headers: HTTPHeaders?
602
        let requestModifier: RequestModifier?
603
 
604
        func asURLRequest() throws -> URLRequest {
605
            var request = try URLRequest(url: url, method: method, headers: headers)
606
            try requestModifier?(&request)
607
 
608
            return request
609
        }
610
    }
611
 
612
    struct Upload: UploadConvertible {
613
        let request: URLRequestConvertible
614
        let uploadable: UploadableConvertible
615
 
616
        func createUploadable() throws -> UploadRequest.Uploadable {
617
            try uploadable.createUploadable()
618
        }
619
 
620
        func asURLRequest() throws -> URLRequest {
621
            try request.asURLRequest()
622
        }
623
    }
624
 
625
    // MARK: Data
626
 
627
    /// Creates an `UploadRequest` for the given `Data`, `URLRequest` components, and `RequestInterceptor`.
628
    ///
629
    /// - Parameters:
630
    ///   - data:            The `Data` to upload.
631
    ///   - convertible:     `URLConvertible` value to be used as the `URLRequest`'s `URL`.
632
    ///   - method:          `HTTPMethod` for the `URLRequest`. `.post` by default.
633
    ///   - headers:         `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
634
    ///   - interceptor:     `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
635
    ///   - fileManager:     `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by
636
    ///                      default.
637
    ///   - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided
638
    ///                      parameters. `nil` by default.
639
    ///
640
    /// - Returns:           The created `UploadRequest`.
641
    open func upload(_ data: Data,
642
                     to convertible: URLConvertible,
643
                     method: HTTPMethod = .post,
644
                     headers: HTTPHeaders? = nil,
645
                     interceptor: RequestInterceptor? = nil,
646
                     fileManager: FileManager = .default,
647
                     requestModifier: RequestModifier? = nil) -> UploadRequest {
648
        let convertible = ParameterlessRequestConvertible(url: convertible,
649
                                                          method: method,
650
                                                          headers: headers,
651
                                                          requestModifier: requestModifier)
652
 
653
        return upload(data, with: convertible, interceptor: interceptor, fileManager: fileManager)
654
    }
655
 
656
    /// Creates an `UploadRequest` for the given `Data` using the `URLRequestConvertible` value and `RequestInterceptor`.
657
    ///
658
    /// - Parameters:
659
    ///   - data:        The `Data` to upload.
660
    ///   - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`.
661
    ///   - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
662
    ///   - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by
663
    ///                  default.
664
    ///
665
    /// - Returns:       The created `UploadRequest`.
666
    open func upload(_ data: Data,
667
                     with convertible: URLRequestConvertible,
668
                     interceptor: RequestInterceptor? = nil,
669
                     fileManager: FileManager = .default) -> UploadRequest {
670
        upload(.data(data), with: convertible, interceptor: interceptor, fileManager: fileManager)
671
    }
672
 
673
    // MARK: File
674
 
675
    /// Creates an `UploadRequest` for the file at the given file `URL`, using a `URLRequest` from the provided
676
    /// components and `RequestInterceptor`.
677
    ///
678
    /// - Parameters:
679
    ///   - fileURL:         The `URL` of the file to upload.
680
    ///   - convertible:     `URLConvertible` value to be used as the `URLRequest`'s `URL`.
681
    ///   - method:          `HTTPMethod` for the `URLRequest`. `.post` by default.
682
    ///   - headers:         `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
683
    ///   - interceptor:     `RequestInterceptor` value to be used by the returned `UploadRequest`. `nil` by default.
684
    ///   - fileManager:     `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by
685
    ///                      default.
686
    ///   - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided
687
    ///                      parameters. `nil` by default.
688
    ///
689
    /// - Returns:           The created `UploadRequest`.
690
    open func upload(_ fileURL: URL,
691
                     to convertible: URLConvertible,
692
                     method: HTTPMethod = .post,
693
                     headers: HTTPHeaders? = nil,
694
                     interceptor: RequestInterceptor? = nil,
695
                     fileManager: FileManager = .default,
696
                     requestModifier: RequestModifier? = nil) -> UploadRequest {
697
        let convertible = ParameterlessRequestConvertible(url: convertible,
698
                                                          method: method,
699
                                                          headers: headers,
700
                                                          requestModifier: requestModifier)
701
 
702
        return upload(fileURL, with: convertible, interceptor: interceptor, fileManager: fileManager)
703
    }
704
 
705
    /// Creates an `UploadRequest` for the file at the given file `URL` using the `URLRequestConvertible` value and
706
    /// `RequestInterceptor`.
707
    ///
708
    /// - Parameters:
709
    ///   - fileURL:     The `URL` of the file to upload.
710
    ///   - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`.
711
    ///   - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
712
    ///   - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by
713
    ///                  default.
714
    ///
715
    /// - Returns:       The created `UploadRequest`.
716
    open func upload(_ fileURL: URL,
717
                     with convertible: URLRequestConvertible,
718
                     interceptor: RequestInterceptor? = nil,
719
                     fileManager: FileManager = .default) -> UploadRequest {
720
        upload(.file(fileURL, shouldRemove: false), with: convertible, interceptor: interceptor, fileManager: fileManager)
721
    }
722
 
723
    // MARK: InputStream
724
 
725
    /// Creates an `UploadRequest` from the `InputStream` provided using a `URLRequest` from the provided components and
726
    /// `RequestInterceptor`.
727
    ///
728
    /// - Parameters:
729
    ///   - stream:          The `InputStream` that provides the data to upload.
730
    ///   - convertible:     `URLConvertible` value to be used as the `URLRequest`'s `URL`.
731
    ///   - method:          `HTTPMethod` for the `URLRequest`. `.post` by default.
732
    ///   - headers:         `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
733
    ///   - interceptor:     `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
734
    ///   - fileManager:     `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by
735
    ///                      default.
736
    ///   - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided
737
    ///                      parameters. `nil` by default.
738
    ///
739
    /// - Returns:           The created `UploadRequest`.
740
    open func upload(_ stream: InputStream,
741
                     to convertible: URLConvertible,
742
                     method: HTTPMethod = .post,
743
                     headers: HTTPHeaders? = nil,
744
                     interceptor: RequestInterceptor? = nil,
745
                     fileManager: FileManager = .default,
746
                     requestModifier: RequestModifier? = nil) -> UploadRequest {
747
        let convertible = ParameterlessRequestConvertible(url: convertible,
748
                                                          method: method,
749
                                                          headers: headers,
750
                                                          requestModifier: requestModifier)
751
 
752
        return upload(stream, with: convertible, interceptor: interceptor, fileManager: fileManager)
753
    }
754
 
755
    /// Creates an `UploadRequest` from the provided `InputStream` using the `URLRequestConvertible` value and
756
    /// `RequestInterceptor`.
757
    ///
758
    /// - Parameters:
759
    ///   - stream:      The `InputStream` that provides the data to upload.
760
    ///   - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`.
761
    ///   - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
762
    ///   - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by
763
    ///                  default.
764
    ///
765
    /// - Returns:       The created `UploadRequest`.
766
    open func upload(_ stream: InputStream,
767
                     with convertible: URLRequestConvertible,
768
                     interceptor: RequestInterceptor? = nil,
769
                     fileManager: FileManager = .default) -> UploadRequest {
770
        upload(.stream(stream), with: convertible, interceptor: interceptor, fileManager: fileManager)
771
    }
772
 
773
    // MARK: MultipartFormData
774
 
775
    /// Creates an `UploadRequest` for the multipart form data built using a closure and sent using the provided
776
    /// `URLRequest` components and `RequestInterceptor`.
777
    ///
778
    /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cumulative
779
    /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
780
    /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
781
    /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
782
    /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
783
    /// used for larger payloads such as video content.
784
    ///
785
    /// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
786
    /// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
787
    /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
788
    /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
789
    /// technique was used.
790
    ///
791
    /// - Parameters:
792
    ///   - multipartFormData:      `MultipartFormData` building closure.
793
    ///   - url:                    `URLConvertible` value to be used as the `URLRequest`'s `URL`.
794
    ///   - encodingMemoryThreshold: Byte threshold used to determine whether the form data is encoded into memory or
795
    ///                              onto disk before being uploaded. `MultipartFormData.encodingMemoryThreshold` by
796
    ///                              default.
797
    ///   - method:                  `HTTPMethod` for the `URLRequest`. `.post` by default.
798
    ///   - headers:                 `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
799
    ///   - interceptor:             `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
800
    ///   - fileManager:             `FileManager` to be used if the form data exceeds the memory threshold and is
801
    ///                              written to disk before being uploaded. `.default` instance by default.
802
    ///   - requestModifier:         `RequestModifier` which will be applied to the `URLRequest` created from the
803
    ///                              provided parameters. `nil` by default.
804
    ///
805
    /// - Returns:                   The created `UploadRequest`.
806
    open func upload(multipartFormData: @escaping (MultipartFormData) -> Void,
807
                     to url: URLConvertible,
808
                     usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold,
809
                     method: HTTPMethod = .post,
810
                     headers: HTTPHeaders? = nil,
811
                     interceptor: RequestInterceptor? = nil,
812
                     fileManager: FileManager = .default,
813
                     requestModifier: RequestModifier? = nil) -> UploadRequest {
814
        let convertible = ParameterlessRequestConvertible(url: url,
815
                                                          method: method,
816
                                                          headers: headers,
817
                                                          requestModifier: requestModifier)
818
 
819
        let formData = MultipartFormData(fileManager: fileManager)
820
        multipartFormData(formData)
821
 
822
        return upload(multipartFormData: formData,
823
                      with: convertible,
824
                      usingThreshold: encodingMemoryThreshold,
825
                      interceptor: interceptor,
826
                      fileManager: fileManager)
827
    }
828
 
829
    /// Creates an `UploadRequest` using a `MultipartFormData` building closure, the provided `URLRequestConvertible`
830
    /// value, and a `RequestInterceptor`.
831
    ///
832
    /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cumulative
833
    /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
834
    /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
835
    /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
836
    /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
837
    /// used for larger payloads such as video content.
838
    ///
839
    /// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
840
    /// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
841
    /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
842
    /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
843
    /// technique was used.
844
    ///
845
    /// - Parameters:
846
    ///   - multipartFormData:       `MultipartFormData` building closure.
847
    ///   - request:                 `URLRequestConvertible` value to be used to create the `URLRequest`.
848
    ///   - encodingMemoryThreshold: Byte threshold used to determine whether the form data is encoded into memory or
849
    ///                              onto disk before being uploaded. `MultipartFormData.encodingMemoryThreshold` by
850
    ///                              default.
851
    ///   - interceptor:             `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
852
    ///   - fileManager:             `FileManager` to be used if the form data exceeds the memory threshold and is
853
    ///                              written to disk before being uploaded. `.default` instance by default.
854
    ///
855
    /// - Returns:                   The created `UploadRequest`.
856
    open func upload(multipartFormData: @escaping (MultipartFormData) -> Void,
857
                     with request: URLRequestConvertible,
858
                     usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold,
859
                     interceptor: RequestInterceptor? = nil,
860
                     fileManager: FileManager = .default) -> UploadRequest {
861
        let formData = MultipartFormData(fileManager: fileManager)
862
        multipartFormData(formData)
863
 
864
        return upload(multipartFormData: formData,
865
                      with: request,
866
                      usingThreshold: encodingMemoryThreshold,
867
                      interceptor: interceptor,
868
                      fileManager: fileManager)
869
    }
870
 
871
    /// Creates an `UploadRequest` for the prebuilt `MultipartFormData` value using the provided `URLRequest` components
872
    /// and `RequestInterceptor`.
873
    ///
874
    /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cumulative
875
    /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
876
    /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
877
    /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
878
    /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
879
    /// used for larger payloads such as video content.
880
    ///
881
    /// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
882
    /// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
883
    /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
884
    /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
885
    /// technique was used.
886
    ///
887
    /// - Parameters:
888
    ///   - multipartFormData:       `MultipartFormData` instance to upload.
889
    ///   - url:                     `URLConvertible` value to be used as the `URLRequest`'s `URL`.
890
    ///   - encodingMemoryThreshold: Byte threshold used to determine whether the form data is encoded into memory or
891
    ///                              onto disk before being uploaded. `MultipartFormData.encodingMemoryThreshold` by
892
    ///                              default.
893
    ///   - method:                  `HTTPMethod` for the `URLRequest`. `.post` by default.
894
    ///   - headers:                 `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
895
    ///   - interceptor:             `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
896
    ///   - fileManager:             `FileManager` to be used if the form data exceeds the memory threshold and is
897
    ///                              written to disk before being uploaded. `.default` instance by default.
898
    ///   - requestModifier:         `RequestModifier` which will be applied to the `URLRequest` created from the
899
    ///                              provided parameters. `nil` by default.
900
    ///
901
    /// - Returns:                   The created `UploadRequest`.
902
    open func upload(multipartFormData: MultipartFormData,
903
                     to url: URLConvertible,
904
                     usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold,
905
                     method: HTTPMethod = .post,
906
                     headers: HTTPHeaders? = nil,
907
                     interceptor: RequestInterceptor? = nil,
908
                     fileManager: FileManager = .default,
909
                     requestModifier: RequestModifier? = nil) -> UploadRequest {
910
        let convertible = ParameterlessRequestConvertible(url: url,
911
                                                          method: method,
912
                                                          headers: headers,
913
                                                          requestModifier: requestModifier)
914
 
915
        let multipartUpload = MultipartUpload(encodingMemoryThreshold: encodingMemoryThreshold,
916
                                              request: convertible,
917
                                              multipartFormData: multipartFormData)
918
 
919
        return upload(multipartUpload, interceptor: interceptor, fileManager: fileManager)
920
    }
921
 
922
    /// Creates an `UploadRequest` for the prebuilt `MultipartFormData` value using the providing `URLRequestConvertible`
923
    /// value and `RequestInterceptor`.
924
    ///
925
    /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cumulative
926
    /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
927
    /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
928
    /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
929
    /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
930
    /// used for larger payloads such as video content.
931
    ///
932
    /// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
933
    /// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
934
    /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
935
    /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
936
    /// technique was used.
937
    ///
938
    /// - Parameters:
939
    ///   - multipartFormData:       `MultipartFormData` instance to upload.
940
    ///   - request:                 `URLRequestConvertible` value to be used to create the `URLRequest`.
941
    ///   - encodingMemoryThreshold: Byte threshold used to determine whether the form data is encoded into memory or
942
    ///                              onto disk before being uploaded. `MultipartFormData.encodingMemoryThreshold` by
943
    ///                              default.
944
    ///   - interceptor:             `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
945
    ///   - fileManager:             `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by
946
    ///                              default.
947
    ///
948
    /// - Returns:                   The created `UploadRequest`.
949
    open func upload(multipartFormData: MultipartFormData,
950
                     with request: URLRequestConvertible,
951
                     usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold,
952
                     interceptor: RequestInterceptor? = nil,
953
                     fileManager: FileManager = .default) -> UploadRequest {
954
        let multipartUpload = MultipartUpload(encodingMemoryThreshold: encodingMemoryThreshold,
955
                                              request: request,
956
                                              multipartFormData: multipartFormData)
957
 
958
        return upload(multipartUpload, interceptor: interceptor, fileManager: fileManager)
959
    }
960
 
961
    // MARK: - Internal API
962
 
963
    // MARK: Uploadable
964
 
965
    func upload(_ uploadable: UploadRequest.Uploadable,
966
                with convertible: URLRequestConvertible,
967
                interceptor: RequestInterceptor?,
968
                fileManager: FileManager) -> UploadRequest {
969
        let uploadable = Upload(request: convertible, uploadable: uploadable)
970
 
971
        return upload(uploadable, interceptor: interceptor, fileManager: fileManager)
972
    }
973
 
974
    func upload(_ upload: UploadConvertible, interceptor: RequestInterceptor?, fileManager: FileManager) -> UploadRequest {
975
        let request = UploadRequest(convertible: upload,
976
                                    underlyingQueue: rootQueue,
977
                                    serializationQueue: serializationQueue,
978
                                    eventMonitor: eventMonitor,
979
                                    interceptor: interceptor,
980
                                    fileManager: fileManager,
981
                                    delegate: self)
982
 
983
        perform(request)
984
 
985
        return request
986
    }
987
 
988
    // MARK: Perform
989
 
990
    /// Starts performing the provided `Request`.
991
    ///
992
    /// - Parameter request: The `Request` to perform.
993
    func perform(_ request: Request) {
994
        rootQueue.async {
995
            guard !request.isCancelled else { return }
996
 
997
            self.activeRequests.insert(request)
998
 
999
            self.requestQueue.async {
1000
                // Leaf types must come first, otherwise they will cast as their superclass.
1001
                switch request {
1002
                case let r as UploadRequest: self.performUploadRequest(r) // UploadRequest must come before DataRequest due to subtype relationship.
1003
                case let r as DataRequest: self.performDataRequest(r)
1004
                case let r as DownloadRequest: self.performDownloadRequest(r)
1005
                case let r as DataStreamRequest: self.performDataStreamRequest(r)
1006
                default: fatalError("Attempted to perform unsupported Request subclass: \(type(of: request))")
1007
                }
1008
            }
1009
        }
1010
    }
1011
 
1012
    func performDataRequest(_ request: DataRequest) {
1013
        dispatchPrecondition(condition: .onQueue(requestQueue))
1014
 
1015
        performSetupOperations(for: request, convertible: request.convertible)
1016
    }
1017
 
1018
    func performDataStreamRequest(_ request: DataStreamRequest) {
1019
        dispatchPrecondition(condition: .onQueue(requestQueue))
1020
 
1021
        performSetupOperations(for: request, convertible: request.convertible)
1022
    }
1023
 
1024
    func performUploadRequest(_ request: UploadRequest) {
1025
        dispatchPrecondition(condition: .onQueue(requestQueue))
1026
 
1027
        performSetupOperations(for: request, convertible: request.convertible) {
1028
            do {
1029
                let uploadable = try request.upload.createUploadable()
1030
                self.rootQueue.async { request.didCreateUploadable(uploadable) }
1031
                return true
1032
            } catch {
1033
                self.rootQueue.async { request.didFailToCreateUploadable(with: error.asAFError(or: .createUploadableFailed(error: error))) }
1034
                return false
1035
            }
1036
        }
1037
    }
1038
 
1039
    func performDownloadRequest(_ request: DownloadRequest) {
1040
        dispatchPrecondition(condition: .onQueue(requestQueue))
1041
 
1042
        switch request.downloadable {
1043
        case let .request(convertible):
1044
            performSetupOperations(for: request, convertible: convertible)
1045
        case let .resumeData(resumeData):
1046
            rootQueue.async { self.didReceiveResumeData(resumeData, for: request) }
1047
        }
1048
    }
1049
 
1050
    func performSetupOperations(for request: Request,
1051
                                convertible: URLRequestConvertible,
1052
                                shouldCreateTask: @escaping () -> Bool = { true }) {
1053
        dispatchPrecondition(condition: .onQueue(requestQueue))
1054
 
1055
        let initialRequest: URLRequest
1056
 
1057
        do {
1058
            initialRequest = try convertible.asURLRequest()
1059
            try initialRequest.validate()
1060
        } catch {
1061
            rootQueue.async { request.didFailToCreateURLRequest(with: error.asAFError(or: .createURLRequestFailed(error: error))) }
1062
            return
1063
        }
1064
 
1065
        rootQueue.async { request.didCreateInitialURLRequest(initialRequest) }
1066
 
1067
        guard !request.isCancelled else { return }
1068
 
1069
        guard let adapter = adapter(for: request) else {
1070
            guard shouldCreateTask() else { return }
1071
            rootQueue.async { self.didCreateURLRequest(initialRequest, for: request) }
1072
            return
1073
        }
1074
 
1075
        let adapterState = RequestAdapterState(requestID: request.id, session: self)
1076
 
1077
        adapter.adapt(initialRequest, using: adapterState) { result in
1078
            do {
1079
                let adaptedRequest = try result.get()
1080
                try adaptedRequest.validate()
1081
 
1082
                self.rootQueue.async { request.didAdaptInitialRequest(initialRequest, to: adaptedRequest) }
1083
 
1084
                guard shouldCreateTask() else { return }
1085
 
1086
                self.rootQueue.async { self.didCreateURLRequest(adaptedRequest, for: request) }
1087
            } catch {
1088
                self.rootQueue.async { request.didFailToAdaptURLRequest(initialRequest, withError: .requestAdaptationFailed(error: error)) }
1089
            }
1090
        }
1091
    }
1092
 
1093
    // MARK: - Task Handling
1094
 
1095
    func didCreateURLRequest(_ urlRequest: URLRequest, for request: Request) {
1096
        dispatchPrecondition(condition: .onQueue(rootQueue))
1097
 
1098
        request.didCreateURLRequest(urlRequest)
1099
 
1100
        guard !request.isCancelled else { return }
1101
 
1102
        let task = request.task(for: urlRequest, using: session)
1103
        requestTaskMap[request] = task
1104
        request.didCreateTask(task)
1105
 
1106
        updateStatesForTask(task, request: request)
1107
    }
1108
 
1109
    func didReceiveResumeData(_ data: Data, for request: DownloadRequest) {
1110
        dispatchPrecondition(condition: .onQueue(rootQueue))
1111
 
1112
        guard !request.isCancelled else { return }
1113
 
1114
        let task = request.task(forResumeData: data, using: session)
1115
        requestTaskMap[request] = task
1116
        request.didCreateTask(task)
1117
 
1118
        updateStatesForTask(task, request: request)
1119
    }
1120
 
1121
    func updateStatesForTask(_ task: URLSessionTask, request: Request) {
1122
        dispatchPrecondition(condition: .onQueue(rootQueue))
1123
 
1124
        request.withState { state in
1125
            switch state {
1126
            case .initialized, .finished:
1127
                // Do nothing.
1128
                break
1129
            case .resumed:
1130
                task.resume()
1131
                rootQueue.async { request.didResumeTask(task) }
1132
            case .suspended:
1133
                task.suspend()
1134
                rootQueue.async { request.didSuspendTask(task) }
1135
            case .cancelled:
1136
                // Resume to ensure metrics are gathered.
1137
                task.resume()
1138
                task.cancel()
1139
                rootQueue.async { request.didCancelTask(task) }
1140
            }
1141
        }
1142
    }
1143
 
1144
    // MARK: - Adapters and Retriers
1145
 
1146
    func adapter(for request: Request) -> RequestAdapter? {
1147
        if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor {
1148
            return Interceptor(adapters: [requestInterceptor, sessionInterceptor])
1149
        } else {
1150
            return request.interceptor ?? interceptor
1151
        }
1152
    }
1153
 
1154
    func retrier(for request: Request) -> RequestRetrier? {
1155
        if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor {
1156
            return Interceptor(retriers: [requestInterceptor, sessionInterceptor])
1157
        } else {
1158
            return request.interceptor ?? interceptor
1159
        }
1160
    }
1161
 
1162
    // MARK: - Invalidation
1163
 
1164
    func finishRequestsForDeinit() {
1165
        requestTaskMap.requests.forEach { request in
1166
            rootQueue.async {
1167
                request.finish(error: AFError.sessionDeinitialized)
1168
            }
1169
        }
1170
    }
1171
}
1172
 
1173
// MARK: - RequestDelegate
1174
 
1175
extension Session: RequestDelegate {
1176
    public var sessionConfiguration: URLSessionConfiguration {
1177
        session.configuration
1178
    }
1179
 
1180
    public var startImmediately: Bool { startRequestsImmediately }
1181
 
1182
    public func cleanup(after request: Request) {
1183
        activeRequests.remove(request)
1184
    }
1185
 
1186
    public func retryResult(for request: Request, dueTo error: AFError, completion: @escaping (RetryResult) -> Void) {
1187
        guard let retrier = retrier(for: request) else {
1188
            rootQueue.async { completion(.doNotRetry) }
1189
            return
1190
        }
1191
 
1192
        retrier.retry(request, for: self, dueTo: error) { retryResult in
1193
            self.rootQueue.async {
1194
                guard let retryResultError = retryResult.error else { completion(retryResult); return }
1195
 
1196
                let retryError = AFError.requestRetryFailed(retryError: retryResultError, originalError: error)
1197
                completion(.doNotRetryWithError(retryError))
1198
            }
1199
        }
1200
    }
1201
 
1202
    public func retryRequest(_ request: Request, withDelay timeDelay: TimeInterval?) {
1203
        rootQueue.async {
1204
            let retry: () -> Void = {
1205
                guard !request.isCancelled else { return }
1206
 
1207
                request.prepareForRetry()
1208
                self.perform(request)
1209
            }
1210
 
1211
            if let retryDelay = timeDelay {
1212
                self.rootQueue.after(retryDelay) { retry() }
1213
            } else {
1214
                retry()
1215
            }
1216
        }
1217
    }
1218
}
1219
 
1220
// MARK: - SessionStateProvider
1221
 
1222
extension Session: SessionStateProvider {
1223
    func request(for task: URLSessionTask) -> Request? {
1224
        dispatchPrecondition(condition: .onQueue(rootQueue))
1225
 
1226
        return requestTaskMap[task]
1227
    }
1228
 
1229
    func didGatherMetricsForTask(_ task: URLSessionTask) {
1230
        dispatchPrecondition(condition: .onQueue(rootQueue))
1231
 
1232
        let didDisassociate = requestTaskMap.disassociateIfNecessaryAfterGatheringMetricsForTask(task)
1233
 
1234
        if didDisassociate {
1235
            waitingCompletions[task]?()
1236
            waitingCompletions[task] = nil
1237
        }
1238
    }
1239
 
1240
    func didCompleteTask(_ task: URLSessionTask, completion: @escaping () -> Void) {
1241
        dispatchPrecondition(condition: .onQueue(rootQueue))
1242
 
1243
        let didDisassociate = requestTaskMap.disassociateIfNecessaryAfterCompletingTask(task)
1244
 
1245
        if didDisassociate {
1246
            completion()
1247
        } else {
1248
            waitingCompletions[task] = completion
1249
        }
1250
    }
1251
 
1252
    func credential(for task: URLSessionTask, in protectionSpace: URLProtectionSpace) -> URLCredential? {
1253
        dispatchPrecondition(condition: .onQueue(rootQueue))
1254
 
1255
        return requestTaskMap[task]?.credential ??
1256
            session.configuration.urlCredentialStorage?.defaultCredential(for: protectionSpace)
1257
    }
1258
 
1259
    func cancelRequestsForSessionInvalidation(with error: Error?) {
1260
        dispatchPrecondition(condition: .onQueue(rootQueue))
1261
 
1262
        requestTaskMap.requests.forEach { $0.finish(error: AFError.sessionInvalidated(error: error)) }
1263
    }
1264
}