Repository: vapor/vapor
File: Sources/Vapor/Client/FoundationClient.swift (Swift)

Code before:
                promise.fail(error: error)
                return
            }

            guard let httpResponse = urlResponse as? HTTPURLResponse else {
                let error = VaporError(identifier: "httpURLResponse", reason: "URLResponse was not a HTTPURLResponse.")
                promise.fail(error: error)
                return
            }

            let response = HTTPResponse.convertFromFoundationResponse(httpResponse, data: data, on: self.container)
            promise.succeed(result: Response(http: response, using: self.container))
        }.resume()
        return promise.futureResult
    }
}

// MARK: Private

private extension HTTPRequest {
    /// Converts an `HTTP.HTTPRequest` to `Foundation.URLRequest`
    func convertToFoundationRequest() -> URLRequest {
        let http = self
        let body = http.body.data ?? Data()
        var request = URLRequest(url: http.url)
        request.httpMethod = "\(http.method)"
        request.httpBody = body
        http.headers.forEach { key, val in
            request.addValue(val, forHTTPHeaderField: key.description)
        }
        return request
    }
}

private extension HTTPResponse {
    /// Creates an `HTTP.HTTPResponse` to `Foundation.URLResponse`
    static func convertFromFoundationResponse(_ httpResponse: HTTPURLResponse, data: Data?, on worker: Worker) -> HTTPResponse {
        var res = HTTPResponse(status: .init(statusCode: httpResponse.statusCode))
        if let data = data {
            res.body = HTTPBody(data: data)
        }
        for (key, value) in httpResponse.allHeaderFields {
            res.headers.replaceOrAdd(name: "\(key)", value: "\(value)")
        }
        return res
    }
}


Review comment (performance):
I think `defaultCachePolicy` is kind of a confusing label here since it's never replaced by anything, but it's an internal API so not a huge deal.

Code after:
        let urlReq = req.http.convertToFoundationRequest(defaultCachePolicy: cachePolicy)
        let promise = req.eventLoop.newPromise(Response.self)
        self.urlSession.dataTask(with: urlReq) { data, urlResponse, error in
            if let error = error {
                promise.fail(error: error)
                return
            }

            guard let httpResponse = urlResponse as? HTTPURLResponse else {
                let error = VaporError(identifier: "httpURLResponse", reason: "URLResponse was not a HTTPURLResponse.")
                promise.fail(error: error)
                return
            }

            let response = HTTPResponse.convertFromFoundationResponse(httpResponse, data: data, on: self.container)
            promise.succeed(result: Response(http: response, using: self.container))
        }.resume()
        return promise.futureResult
    }
}

// MARK: Private

private extension HTTPRequest {
    /// Converts an `HTTP.HTTPRequest` to `Foundation.URLRequest`
    func convertToFoundationRequest(defaultCachePolicy cachePolicy: URLRequest.CachePolicy?) -> URLRequest {
        let http = self
        let body = http.body.data ?? Data()
        var request = URLRequest(url: http.url)
        request.httpMethod = "\(http.method)"
        request.httpBody = body
        if let cachePolicy = cachePolicy {
            request.cachePolicy = cachePolicy
        }
        http.headers.forEach { key, val in
            request.addValue(val, forHTTPHeaderField: key.description)
        }
        return request
    }
}

private extension HTTPResponse {
    /// Creates an `HTTP.HTTPResponse` to `Foundation.URLResponse`
    static func convertFromFoundationResponse(_ httpResponse: HTTPURLResponse, data: Data?, on worker: Worker) -> HTTPResponse {
        var res = HTTPResponse(status: .init(statusCode: httpResponse.statusCode))
        if let data = data {
            res.body = HTTPBody(data: data)
        }
        for (key, value) in httpResponse.allHeaderFields {
            res.headers.replaceOrAdd(name: "\(key)", value: "\(value)")
        }