Skip to content

Commit 843fa26

Browse files
committed
add URLSession+HTTPRequest for Linux, Windows Swift 5.x
1 parent 02fd09b commit 843fa26

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import Foundation
2+
import HTTPTypes
3+
4+
#if canImport(FoundationNetworking)
5+
import FoundationNetworking
6+
#endif
7+
8+
#if !os(WASI)
9+
10+
extension URLSessionTask {
11+
/// The original HTTP request this task was created with.
12+
public var originalHTTPRequest: HTTPRequest? {
13+
self.originalRequest?.httpRequest
14+
}
15+
16+
/// The current HTTP request -- may differ from the `originalHTTPRequest` due to HTTP redirection.
17+
public var currentHTTPRequest: HTTPRequest? {
18+
self.currentRequest?.httpRequest
19+
}
20+
21+
/// The HTTP response received from the server.
22+
public var httpResponse: HTTPResponse? {
23+
(self.response as? HTTPURLResponse)?.httpResponse
24+
}
25+
}
26+
27+
private enum HTTPTypeConversionError: Error {
28+
case failedToConvertHTTPRequestToURLRequest
29+
case failedToConvertURLResponseToHTTPResponse
30+
}
31+
32+
#endif
33+
34+
#if (os(Linux) || os(Windows)) && compiler(<6)
35+
36+
@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)
37+
extension URLSession {
38+
/// Convenience method to load data using an `HTTPRequest`; creates and resumes a `URLSessionDataTask` internally.
39+
///
40+
/// - Parameter request: The `HTTPRequest` for which to load data.
41+
/// - Parameter delegate: Task-specific delegate.
42+
/// - Returns: Data and response.
43+
public func data(
44+
for request: HTTPRequest,
45+
delegate: (any URLSessionTaskDelegate)? = nil
46+
) async throws -> (Data, HTTPResponse) {
47+
guard let urlRequest = URLRequest(httpRequest: request) else {
48+
throw HTTPTypeConversionError.failedToConvertHTTPRequestToURLRequest
49+
}
50+
let (data, urlResponse) = try await self.data(for: urlRequest, delegate: delegate)
51+
guard let response = (urlResponse as? HTTPURLResponse)?.httpResponse else {
52+
throw HTTPTypeConversionError.failedToConvertURLResponseToHTTPResponse
53+
}
54+
return (data, response)
55+
}
56+
57+
/// Convenience method to upload data using an `HTTPRequest`; creates and resumes a `URLSessionUploadTask` internally.
58+
///
59+
/// - Parameter request: The `HTTPRequest` for which to upload data.
60+
/// - Parameter fileURL: File to upload.
61+
/// - Parameter delegate: Task-specific delegate.
62+
/// - Returns: Data and response.
63+
public func upload(
64+
for request: HTTPRequest,
65+
fromFile fileURL: URL,
66+
delegate: (any URLSessionTaskDelegate)? = nil
67+
) async throws -> (Data, HTTPResponse) {
68+
guard let urlRequest = URLRequest(httpRequest: request) else {
69+
throw HTTPTypeConversionError.failedToConvertHTTPRequestToURLRequest
70+
}
71+
let (data, urlResponse) = try await self.upload(for: urlRequest, fromFile: fileURL, delegate: delegate)
72+
guard let response = (urlResponse as? HTTPURLResponse)?.httpResponse else {
73+
throw HTTPTypeConversionError.failedToConvertURLResponseToHTTPResponse
74+
}
75+
return (data, response)
76+
}
77+
78+
/// Convenience method to upload data using an `HTTPRequest`, creates and resumes a `URLSessionUploadTask` internally.
79+
///
80+
/// - Parameter request: The `HTTPRequest` for which to upload data.
81+
/// - Parameter bodyData: Data to upload.
82+
/// - Parameter delegate: Task-specific delegate.
83+
/// - Returns: Data and response.
84+
public func upload(
85+
for request: HTTPRequest,
86+
from bodyData: Data,
87+
delegate: (any URLSessionTaskDelegate)? = nil
88+
) async throws -> (Data, HTTPResponse) {
89+
guard let urlRequest = URLRequest(httpRequest: request) else {
90+
throw HTTPTypeConversionError.failedToConvertHTTPRequestToURLRequest
91+
}
92+
let (data, urlResponse) = try await self.upload(for: urlRequest, from: bodyData, delegate: delegate)
93+
guard let response = (urlResponse as? HTTPURLResponse)?.httpResponse else {
94+
throw HTTPTypeConversionError.failedToConvertURLResponseToHTTPResponse
95+
}
96+
return (data, response)
97+
}
98+
99+
/// Convenience method to download using an `HTTPRequest`; creates and resumes a `URLSessionDownloadTask` internally.
100+
///
101+
/// - Parameter request: The `HTTPRequest` for which to download.
102+
/// - Parameter delegate: Task-specific delegate.
103+
/// - Returns: Downloaded file URL and response. The file will not be removed automatically.
104+
public func download(
105+
for request: HTTPRequest,
106+
delegate: (any URLSessionTaskDelegate)? = nil
107+
) async throws -> (URL, HTTPResponse) {
108+
guard let urlRequest = URLRequest(httpRequest: request) else {
109+
throw HTTPTypeConversionError.failedToConvertHTTPRequestToURLRequest
110+
}
111+
let (location, urlResponse) = try await self.download(for: urlRequest, delegate: delegate)
112+
guard let response = (urlResponse as? HTTPURLResponse)?.httpResponse else {
113+
throw HTTPTypeConversionError.failedToConvertURLResponseToHTTPResponse
114+
}
115+
return (location, response)
116+
}
117+
118+
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || (compiler(>=6) && os(visionOS))
119+
/// Returns a byte stream that conforms to AsyncSequence protocol.
120+
///
121+
/// - Parameter request: The `HTTPRequest` for which to load data.
122+
/// - Parameter delegate: Task-specific delegate.
123+
/// - Returns: Data stream and response.
124+
public func bytes(
125+
for request: HTTPRequest,
126+
delegate: (any URLSessionTaskDelegate)? = nil
127+
) async throws -> (AsyncBytes, HTTPResponse) {
128+
guard let urlRequest = URLRequest(httpRequest: request) else {
129+
throw HTTPTypeConversionError.failedToConvertHTTPRequestToURLRequest
130+
}
131+
let (data, urlResponse) = try await self.bytes(for: urlRequest, delegate: delegate)
132+
guard let response = (urlResponse as? HTTPURLResponse)?.httpResponse else {
133+
throw HTTPTypeConversionError.failedToConvertURLResponseToHTTPResponse
134+
}
135+
return (data, response)
136+
}
137+
#endif
138+
}
139+
140+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
141+
extension URLSession {
142+
/// Convenience method to load data using an `HTTPRequest`; creates and resumes a `URLSessionDataTask` internally.
143+
///
144+
/// - Parameter request: The `HTTPRequest` for which to load data.
145+
/// - Returns: Data and response.
146+
public func data(for request: HTTPRequest) async throws -> (Data, HTTPResponse) {
147+
guard let urlRequest = URLRequest(httpRequest: request) else {
148+
throw HTTPTypeConversionError.failedToConvertHTTPRequestToURLRequest
149+
}
150+
let (data, urlResponse) = try await self.data(for: urlRequest)
151+
guard let response = (urlResponse as? HTTPURLResponse)?.httpResponse else {
152+
throw HTTPTypeConversionError.failedToConvertURLResponseToHTTPResponse
153+
}
154+
return (data, response)
155+
}
156+
157+
/// Convenience method to upload data using an `HTTPRequest`; creates and resumes a `URLSessionUploadTask` internally.
158+
///
159+
/// - Parameter request: The `HTTPRequest` for which to upload data.
160+
/// - Parameter fileURL: File to upload.
161+
/// - Returns: Data and response.
162+
public func upload(for request: HTTPRequest, fromFile fileURL: URL) async throws -> (Data, HTTPResponse) {
163+
guard let urlRequest = URLRequest(httpRequest: request) else {
164+
throw HTTPTypeConversionError.failedToConvertHTTPRequestToURLRequest
165+
}
166+
let (data, urlResponse) = try await self.upload(for: urlRequest, fromFile: fileURL)
167+
guard let response = (urlResponse as? HTTPURLResponse)?.httpResponse else {
168+
throw HTTPTypeConversionError.failedToConvertURLResponseToHTTPResponse
169+
}
170+
return (data, response)
171+
}
172+
173+
/// Convenience method to upload data using an `HTTPRequest`, creates and resumes a `URLSessionUploadTask` internally.
174+
///
175+
/// - Parameter request: The `HTTPRequest` for which to upload data.
176+
/// - Parameter bodyData: Data to upload.
177+
/// - Returns: Data and response.
178+
public func upload(for request: HTTPRequest, from bodyData: Data) async throws -> (Data, HTTPResponse) {
179+
guard let urlRequest = URLRequest(httpRequest: request) else {
180+
throw HTTPTypeConversionError.failedToConvertHTTPRequestToURLRequest
181+
}
182+
let (data, urlResponse) = try await self.upload(for: urlRequest, from: bodyData)
183+
guard let response = (urlResponse as? HTTPURLResponse)?.httpResponse else {
184+
throw HTTPTypeConversionError.failedToConvertURLResponseToHTTPResponse
185+
}
186+
return (data, response)
187+
}
188+
}
189+
190+
#endif

0 commit comments

Comments
 (0)