mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-26 18:21:00 +00:00
Fix a crash bug at Client.makeURL
(#1601)
The crash will happen when you type something unexpected instance URL.
Example
```swift
let server = "mstdn.jp/"
var components = URLComponents()
components.scheme = "https"
components.host = server
components.path = "/api/v1/instance"
components.url! // 💥 error: Execution was interrupted, reason: EXC_BREAKPOINT (code=1, subcode=0x18c986650).
```
This commit is contained in:
parent
23a83d69cc
commit
e3f7eb31e4
2 changed files with 28 additions and 17 deletions
|
@ -40,9 +40,14 @@ import Observation
|
||||||
}
|
}
|
||||||
|
|
||||||
private func connect() {
|
private func connect() {
|
||||||
guard let client else { return }
|
guard let task = try? client?.makeWebSocketTask(
|
||||||
task = client.makeWebSocketTask(endpoint: Streaming.streaming, instanceStreamingURL: instanceStreamingURL)
|
endpoint: Streaming.streaming,
|
||||||
task?.resume()
|
instanceStreamingURL: instanceStreamingURL
|
||||||
|
) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.task = task
|
||||||
|
self.task?.resume()
|
||||||
receiveMessage()
|
receiveMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,10 @@ import SwiftUI
|
||||||
case v1, v2
|
case v1, v2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ClientError: Error {
|
||||||
|
case unexpectedRequest
|
||||||
|
}
|
||||||
|
|
||||||
public enum OauthError: Error {
|
public enum OauthError: Error {
|
||||||
case missingApp
|
case missingApp
|
||||||
case invalidRedirectURL
|
case invalidRedirectURL
|
||||||
|
@ -89,8 +93,7 @@ import SwiftUI
|
||||||
private func makeURL(scheme: String = "https",
|
private func makeURL(scheme: String = "https",
|
||||||
endpoint: Endpoint,
|
endpoint: Endpoint,
|
||||||
forceVersion: Version? = nil,
|
forceVersion: Version? = nil,
|
||||||
forceServer: String? = nil) -> URL
|
forceServer: String? = nil) throws -> URL {
|
||||||
{
|
|
||||||
var components = URLComponents()
|
var components = URLComponents()
|
||||||
components.scheme = scheme
|
components.scheme = scheme
|
||||||
components.host = forceServer ?? server
|
components.host = forceServer ?? server
|
||||||
|
@ -100,7 +103,10 @@ import SwiftUI
|
||||||
components.path += "/api/\(forceVersion?.rawValue ?? version.rawValue)/\(endpoint.path())"
|
components.path += "/api/\(forceVersion?.rawValue ?? version.rawValue)/\(endpoint.path())"
|
||||||
}
|
}
|
||||||
components.queryItems = endpoint.queryItems()
|
components.queryItems = endpoint.queryItems()
|
||||||
return components.url!
|
guard let url = components.url else {
|
||||||
|
throw ClientError.unexpectedRequest
|
||||||
|
}
|
||||||
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
private func makeURLRequest(url: URL, endpoint: Endpoint, httpMethod: String) -> URLRequest {
|
private func makeURLRequest(url: URL, endpoint: Endpoint, httpMethod: String) -> URLRequest {
|
||||||
|
@ -124,8 +130,8 @@ import SwiftUI
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
private func makeGet(endpoint: Endpoint) -> URLRequest {
|
private func makeGet(endpoint: Endpoint) throws -> URLRequest {
|
||||||
let url = makeURL(endpoint: endpoint)
|
let url = try makeURL(endpoint: endpoint)
|
||||||
return makeURLRequest(url: url, endpoint: endpoint, httpMethod: "GET")
|
return makeURLRequest(url: url, endpoint: endpoint, httpMethod: "GET")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +140,7 @@ import SwiftUI
|
||||||
}
|
}
|
||||||
|
|
||||||
public func getWithLink<Entity: Decodable>(endpoint: Endpoint) async throws -> (Entity, LinkHandler?) {
|
public func getWithLink<Entity: Decodable>(endpoint: Endpoint) async throws -> (Entity, LinkHandler?) {
|
||||||
let (data, httpResponse) = try await urlSession.data(for: makeGet(endpoint: endpoint))
|
let (data, httpResponse) = try await urlSession.data(for: try makeGet(endpoint: endpoint))
|
||||||
var linkHandler: LinkHandler?
|
var linkHandler: LinkHandler?
|
||||||
if let response = httpResponse as? HTTPURLResponse,
|
if let response = httpResponse as? HTTPURLResponse,
|
||||||
let link = response.allHeaderFields["Link"] as? String
|
let link = response.allHeaderFields["Link"] as? String
|
||||||
|
@ -150,14 +156,14 @@ import SwiftUI
|
||||||
}
|
}
|
||||||
|
|
||||||
public func post(endpoint: Endpoint, forceVersion: Version? = nil) async throws -> HTTPURLResponse? {
|
public func post(endpoint: Endpoint, forceVersion: Version? = nil) async throws -> HTTPURLResponse? {
|
||||||
let url = makeURL(endpoint: endpoint, forceVersion: forceVersion)
|
let url = try makeURL(endpoint: endpoint, forceVersion: forceVersion)
|
||||||
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: "POST")
|
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: "POST")
|
||||||
let (_, httpResponse) = try await urlSession.data(for: request)
|
let (_, httpResponse) = try await urlSession.data(for: request)
|
||||||
return httpResponse as? HTTPURLResponse
|
return httpResponse as? HTTPURLResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
public func patch(endpoint: Endpoint) async throws -> HTTPURLResponse? {
|
public func patch(endpoint: Endpoint) async throws -> HTTPURLResponse? {
|
||||||
let url = makeURL(endpoint: endpoint)
|
let url = try makeURL(endpoint: endpoint)
|
||||||
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: "PATCH")
|
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: "PATCH")
|
||||||
let (_, httpResponse) = try await urlSession.data(for: request)
|
let (_, httpResponse) = try await urlSession.data(for: request)
|
||||||
return httpResponse as? HTTPURLResponse
|
return httpResponse as? HTTPURLResponse
|
||||||
|
@ -168,7 +174,7 @@ import SwiftUI
|
||||||
}
|
}
|
||||||
|
|
||||||
public func delete(endpoint: Endpoint, forceVersion: Version? = nil) async throws -> HTTPURLResponse? {
|
public func delete(endpoint: Endpoint, forceVersion: Version? = nil) async throws -> HTTPURLResponse? {
|
||||||
let url = makeURL(endpoint: endpoint, forceVersion: forceVersion)
|
let url = try makeURL(endpoint: endpoint, forceVersion: forceVersion)
|
||||||
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: "DELETE")
|
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: "DELETE")
|
||||||
let (_, httpResponse) = try await urlSession.data(for: request)
|
let (_, httpResponse) = try await urlSession.data(for: request)
|
||||||
return httpResponse as? HTTPURLResponse
|
return httpResponse as? HTTPURLResponse
|
||||||
|
@ -178,7 +184,7 @@ import SwiftUI
|
||||||
method: String,
|
method: String,
|
||||||
forceVersion: Version? = nil) async throws -> Entity
|
forceVersion: Version? = nil) async throws -> Entity
|
||||||
{
|
{
|
||||||
let url = makeURL(endpoint: endpoint, forceVersion: forceVersion)
|
let url = try makeURL(endpoint: endpoint, forceVersion: forceVersion)
|
||||||
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: method)
|
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: method)
|
||||||
let (data, httpResponse) = try await urlSession.data(for: request)
|
let (data, httpResponse) = try await urlSession.data(for: request)
|
||||||
logResponseOnError(httpResponse: httpResponse, data: data)
|
logResponseOnError(httpResponse: httpResponse, data: data)
|
||||||
|
@ -198,7 +204,7 @@ import SwiftUI
|
||||||
public func oauthURL() async throws -> URL {
|
public func oauthURL() async throws -> URL {
|
||||||
let app: InstanceApp = try await post(endpoint: Apps.registerApp)
|
let app: InstanceApp = try await post(endpoint: Apps.registerApp)
|
||||||
critical.withLock { $0.oauthApp = app }
|
critical.withLock { $0.oauthApp = app }
|
||||||
return makeURL(endpoint: Oauth.authorize(clientId: app.clientId))
|
return try makeURL(endpoint: Oauth.authorize(clientId: app.clientId))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func continueOauthFlow(url: URL) async throws -> OauthToken {
|
public func continueOauthFlow(url: URL) async throws -> OauthToken {
|
||||||
|
@ -217,8 +223,8 @@ import SwiftUI
|
||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeWebSocketTask(endpoint: Endpoint, instanceStreamingURL: URL?) -> URLSessionWebSocketTask {
|
public func makeWebSocketTask(endpoint: Endpoint, instanceStreamingURL: URL?) throws -> URLSessionWebSocketTask {
|
||||||
let url = makeURL(scheme: "wss", endpoint: endpoint, forceServer: instanceStreamingURL?.host)
|
let url = try makeURL(scheme: "wss", endpoint: endpoint, forceServer: instanceStreamingURL?.host)
|
||||||
var subprotocols: [String] = []
|
var subprotocols: [String] = []
|
||||||
if let oauthToken = critical.withLock({ $0.oauthToken }) {
|
if let oauthToken = critical.withLock({ $0.oauthToken }) {
|
||||||
subprotocols.append(oauthToken.accessToken)
|
subprotocols.append(oauthToken.accessToken)
|
||||||
|
@ -233,7 +239,7 @@ import SwiftUI
|
||||||
filename: String,
|
filename: String,
|
||||||
data: Data) async throws -> Entity
|
data: Data) async throws -> Entity
|
||||||
{
|
{
|
||||||
let url = makeURL(endpoint: endpoint, forceVersion: version)
|
let url = try makeURL(endpoint: endpoint, forceVersion: version)
|
||||||
var request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: method)
|
var request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: method)
|
||||||
let boundary = UUID().uuidString
|
let boundary = UUID().uuidString
|
||||||
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
|
||||||
|
|
Loading…
Reference in a new issue