Skip to content

Commit 64a1d85

Browse files
authored
Merge pull request #213 from cwalo/cwalo/response-body
Provide response body to failed request errors
2 parents c909312 + de8d549 commit 64a1d85

File tree

3 files changed

+51
-27
lines changed

3 files changed

+51
-27
lines changed

Sources/TUSKit/TUSAPI.swift

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
import Foundation
99

1010
/// The errors a TUSAPI can return
11-
public enum TUSAPIError: Error {
11+
public enum TUSAPIError: Error, LocalizedError {
1212
case underlyingError(Error)
1313
case couldNotFetchStatus
1414
case couldNotFetchServerInfo
1515
case couldNotRetrieveOffset
1616
case couldNotRetrieveLocation
17-
case failedRequest(HTTPURLResponse)
18-
17+
case failedRequest(HTTPURLResponse, Data?)
18+
1919
public var localizedDescription: String {
2020
switch self {
2121
case .underlyingError(let error):
@@ -28,10 +28,18 @@ public enum TUSAPIError: Error {
2828
return "Could not retrieve offset from response."
2929
case .couldNotRetrieveLocation:
3030
return "Could not retrieve location from response."
31-
case .failedRequest(let response):
32-
return "Failed request with status code \(response.statusCode)."
31+
case .failedRequest(let response, let data):
32+
if let data, let message = String(data: data, encoding: .utf8) {
33+
return "Failed request with status code \(response.statusCode): \(message)"
34+
} else {
35+
return "Failed request with status code \(response.statusCode)."
36+
}
3337
}
3438
}
39+
40+
public var errorDescription: String? {
41+
localizedDescription
42+
}
3543
}
3644

3745
/// The status of an upload.
@@ -57,8 +65,9 @@ final class TUSAPI {
5765
private let sessionDelegate = SessionDataDelegate()
5866
private let queue = DispatchQueue(label: "com.tus.TUSAPI")
5967
private var backgroundHandler: (() -> Void)? = nil
60-
private var callbacks: [String: (Result<HTTPURLResponse, Error>) -> Void] = [:]
61-
68+
private var callbacks: [String: (Result<(Data?, HTTPURLResponse), Error>) -> Void] = [:]
69+
private var taskData: [String: Data] = [:]
70+
6271
deinit {
6372
if session.delegate is SessionDataDelegate {
6473
session.finishTasksAndInvalidate()
@@ -137,10 +146,10 @@ final class TUSAPI {
137146
queue.sync {
138147
callbacks[identifier] = { result in
139148
processResult(completion: completion) {
140-
let response = try result.get()
141-
149+
let (data, response) = try result.get()
150+
142151
guard (200...299).contains(response.statusCode) else {
143-
throw TUSAPIError.failedRequest(response)
152+
throw TUSAPIError.failedRequest(response, data)
144153
}
145154

146155
guard let lengthStr = response.allHeaderFields[caseInsensitive: "upload-Length"] as? String,
@@ -176,10 +185,10 @@ final class TUSAPI {
176185
queue.sync {
177186
callbacks[identifier] = { result in
178187
processResult(completion: completion) {
179-
let response = try result.get()
180-
188+
let (data, response) = try result.get()
189+
181190
guard (200...299).contains(response.statusCode) else {
182-
throw TUSAPIError.failedRequest(response)
191+
throw TUSAPIError.failedRequest(response, data)
183192
}
184193

185194
guard let location = response.allHeaderFields[caseInsensitive: "location"] as? String,
@@ -281,10 +290,10 @@ final class TUSAPI {
281290
queue.sync {
282291
callbacks[metaData.id.uuidString] = { result in
283292
processResult(completion: completion) {
284-
let response = try result.get()
285-
293+
let (data, response) = try result.get()
294+
286295
guard (200...299).contains(response.statusCode) else {
287-
throw TUSAPIError.failedRequest(response)
296+
throw TUSAPIError.failedRequest(response, data)
288297
}
289298

290299
guard let offsetStr = response.allHeaderFields[caseInsensitive: "upload-offset"] as? String,
@@ -332,7 +341,7 @@ final class TUSAPI {
332341
queue.sync {
333342
self.callbacks[metaData.id.uuidString] = { result in
334343
processResult(completion: completion) {
335-
let response = try result.get()
344+
let (data, response) = try result.get()
336345
guard let offsetStr = response.allHeaderFields[caseInsensitive: "upload-offset"] as? String,
337346
let offset = Int(offsetStr) else {
338347
throw TUSAPIError.couldNotRetrieveOffset
@@ -349,7 +358,7 @@ final class TUSAPI {
349358
queue.sync {
350359
self.callbacks[metadata.id.uuidString] = { result in
351360
processResult(completion: completion) {
352-
let response = try result.get()
361+
let (data, response) = try result.get()
353362
guard let offsetStr = response.allHeaderFields[caseInsensitive: "upload-offset"] as? String,
354363
let offset = Int(offsetStr) else {
355364
throw TUSAPIError.couldNotRetrieveOffset
@@ -436,7 +445,15 @@ extension Dictionary {
436445
private extension TUSAPI {
437446
final class SessionDataDelegate: NSObject, URLSessionDataDelegate {
438447
weak var api: TUSAPI?
439-
448+
449+
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
450+
guard let api, let identifier = dataTask.taskDescription else {
451+
return
452+
}
453+
454+
api.taskData[identifier, default: Data()].append(data)
455+
}
456+
440457
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
441458
api?.handleCompletionOfTask(task, withError: error)
442459
}
@@ -454,6 +471,7 @@ private extension TUSAPI {
454471

455472
defer {
456473
callbacks.removeValue(forKey: identifier)
474+
taskData.removeValue(forKey: identifier)
457475
}
458476

459477
guard let completion = callbacks[identifier] else {
@@ -469,8 +487,10 @@ private extension TUSAPI {
469487
completion(.failure(TUSAPIError.underlyingError(NetworkError.noHTTPURLResponse)))
470488
return
471489
}
472-
473-
completion(.success(response))
490+
491+
let data = taskData[identifier]
492+
let success = (data, response)
493+
completion(.success(success))
474494
}
475495
}
476496

Sources/TUSKit/TUSClientError.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import Foundation
22

33
/// The errors that are passed from TUSClient
4-
public enum TUSClientError: Error {
5-
4+
public enum TUSClientError: Error, LocalizedError {
5+
66
case couldNotCopyFile(underlyingError: Error)
77
case couldNotStoreFile(underlyingError: Error)
88
case fileSizeUnknown
99
case couldNotLoadData(underlyingError: Error)
1010
case couldNotStoreFileMetadata(underlyingError: Error)
11-
case couldNotCreateFileOnServer
11+
case couldNotCreateFileOnServer(underlyingError: Error)
1212
case couldNotUploadFile(underlyingError: Error)
1313
case couldNotGetFileStatus
1414
case fileSizeMismatchWithServer
@@ -36,8 +36,8 @@ public enum TUSClientError: Error {
3636
return "Could not load data: \(underlyingError.localizedDescription)"
3737
case .couldNotStoreFileMetadata(let underlyingError):
3838
return "Could not store file metadata: \(underlyingError.localizedDescription)"
39-
case .couldNotCreateFileOnServer:
40-
return "Could not create file on server."
39+
case .couldNotCreateFileOnServer(let underlyingError):
40+
return "Could not create file on server: (\(underlyingError.localizedDescription))"
4141
case .couldNotUploadFile(let underlyingError):
4242
return "Could not upload file: \(underlyingError.localizedDescription)"
4343
case .couldNotGetFileStatus:
@@ -68,4 +68,8 @@ public enum TUSClientError: Error {
6868
return "Custom URLSession with background configuration is not supported."
6969
}
7070
}
71+
72+
public var errorDescription: String? {
73+
localizedDescription
74+
}
7175
}

Sources/TUSKit/Tasks/CreationTask.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ final class CreationTask: IdentifiableTask {
7070
} catch let error as TUSClientError {
7171
completed(.failure(error))
7272
} catch {
73-
completed(.failure(TUSClientError.couldNotCreateFileOnServer))
73+
completed(.failure(TUSClientError.couldNotCreateFileOnServer(underlyingError: error)))
7474
}
7575
}
7676
}

0 commit comments

Comments
 (0)