Repository: Alamofire/Alamofire
File: Source/Request.swift (Swift)

Code before:
//  THE SOFTWARE.
//

import Foundation

/// Responsible for sending a request and receiving the response and associated data from the server, as well as
/// managing its underlying `URLSessionTask`.
public class Request {
    /// A closure executed once a request has successfully completed in order to determine where to move the temporary
    /// file written to during the download process. The closure takes two arguments: the temporary file URL and the URL
    /// response, and returns a single argument: the file URL where the temporary file should be moved.
    public typealias DownloadFileDestination = (URL, HTTPURLResponse) -> URL

    // MARK: Properties

    /// The delegate for the underlying task.
    public let delegate: TaskDelegate

    /// The underlying task.
    public var task: URLSessionTask { return delegate.task }

    /// The session belonging to the underlying task.
    public let session: URLSession

    /// The request sent or to be sent to the server.
    public var request: URLRequest? { return task.originalRequest }

    /// The response received from the server, if any.
    public var response: HTTPURLResponse? { return task.response as? HTTPURLResponse }

    /// The progress of the request lifecycle.
    public var progress: Progress { return delegate.progress }

    /// The resume data of the underlying download task if available after a failure.
    public var resumeData: Data? {
        var data: Data?

        if let delegate = delegate as? DownloadTaskDelegate {
            data = delegate.resumeData
        }

        return data
    }

    var startTime: CFAbsoluteTime?
    var endTime: CFAbsoluteTime?

    // MARK: Lifecycle

    init(session: URLSession, task: URLSessionTask) {
        self.session = session

Review comment (suggestion):
This may be overkill to wrap the change here in a lock, but I figure it's better safe than sorry. The only time this can ever change is when a data task is converted to a download task. Previously we were changing the subdelegate and not actually updating the request. That then created a mismatch between what the `Request` delegate reported and what was actually called.


Code after:
//  THE SOFTWARE.
//

import Foundation

/// Responsible for sending a request and receiving the response and associated data from the server, as well as
/// managing its underlying `URLSessionTask`.
public class Request {
    /// A closure executed once a request has successfully completed in order to determine where to move the temporary
    /// file written to during the download process. The closure takes two arguments: the temporary file URL and the URL
    /// response, and returns a single argument: the file URL where the temporary file should be moved.
    public typealias DownloadFileDestination = (URL, HTTPURLResponse) -> URL

    // MARK: Properties

    /// The delegate for the underlying task.
    public internal(set) var delegate: TaskDelegate {
        get {
            taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }
            return taskDelegate
        }
        set {
            taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }
            taskDelegate = newValue
        }
    }

    /// The underlying task.
    public var task: URLSessionTask { return delegate.task }

    /// The session belonging to the underlying task.
    public let session: URLSession

    /// The request sent or to be sent to the server.
    public var request: URLRequest? { return task.originalRequest }

    /// The response received from the server, if any.
    public var response: HTTPURLResponse? { return task.response as? HTTPURLResponse }

    /// The progress of the request lifecycle.
    public var progress: Progress { return delegate.progress }

    /// The resume data of the underlying download task if available after a failure.
    public var resumeData: Data? {
        var data: Data?

        if let delegate = delegate as? DownloadTaskDelegate {
            data = delegate.resumeData
        }

        return data