forked from vapor/vapor
/
FoundationClient.swift
86 lines (74 loc) 路 2.96 KB
/
FoundationClient.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
/// `Client` wrapper around `Foundation.URLSession`.
public final class FoundationClient: Client, ServiceType {
/// See `ServiceType`.
public static var serviceSupports: [Any.Type] {
return [Client.self]
}
/// See `ServiceType`.
public static func makeService(for worker: Container) throws -> FoundationClient {
return .default(on: worker)
}
/// See `Client`.
public let container: Container
/// The `URLSession` powering this client.
private let urlSession: URLSession
/// Creates a new `FoundationClient`.
public init(_ urlSession: URLSession, on container: Container) {
self.urlSession = urlSession
self.container = container
}
/// Creates a `FoundationClient` with default settings.
public static func `default`(on container: Container) -> FoundationClient {
return .init(.init(configuration: .default), on: container)
}
/// See `Client`.
public func send(_ req: Request) -> Future<Response> {
let urlReq = req.http.convertToFoundationRequest()
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() -> 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
}
}