Skip to content

Commit 068a16e

Browse files
Merge pull request #177 from nextcloud/error-improvements
fix upload - error
2 parents c39a179 + 48bc168 commit 068a16e

3 files changed

Lines changed: 32 additions & 33 deletions

File tree

Sources/NextcloudKit/NKError.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ public struct NKError: Error, Equatable {
4949
public static let forbiddenError = NKError(errorCode: 403, errorDescription: NSLocalizedString("_forbidden_", value: "Forbidden", comment: ""))
5050
public static let cancelled = NKError(errorCode: -999, errorDescription: NSLocalizedString("_cancelled_", value: "Cancelled", comment: ""))
5151

52-
public static let uploadIncomplete = NKError(errorCode: -9992, errorDescription: NSLocalizedString("_upload_incomplete_", value: "Upload incomplete", comment: ""))
53-
54-
public static let errorChunkFileUpload = NKError(errorCode: -9993, errorDescription: NSLocalizedString("_upload_incomplete_", value: "Upload incomplete", comment: ""))
5552
public static let errorChunkFileNull = NKError(errorCode: -9994, errorDescription: NSLocalizedString("_error_file_null_", value: "File not found", comment: ""))
5653
public static let errorChunkFilesEmpty = NKError(errorCode: -9995, errorDescription: NSLocalizedString("_chunk_files_empty_", value: "Files not found", comment: ""))
5754
public static let errorChunkCreateFolder = NKError(errorCode: -9996, errorDescription: NSLocalizedString("_error_create_folder_", value: "Create folder error", comment: ""))

Sources/NextcloudKit/NextcloudKit+Upload.swift

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,9 @@ public extension NextcloudKit {
3838
requestHandler: @escaping (_ request: UploadRequest) -> Void = { _ in },
3939
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in },
4040
progressHandler: @escaping (_ progress: Progress) -> Void = { _ in },
41-
completionHandler: @escaping (_ account: String, _ ocId: String?, _ etag: String?, _ date: Date?, _ size: Int64, _ headers: [AnyHashable: Any]?, _ nkError: NKError) -> Void) {
41+
completionHandler: @escaping (_ account: String, _ ocId: String?, _ etag: String?, _ date: Date?, _ size: Int64, _ response: AFDataResponse<Data>?, _ nkError: NKError) -> Void) {
4242
var convertible: URLConvertible?
4343
var uploadedSize: Int64 = 0
44-
var uploadCompleted = false
4544

4645
if serverUrlFileName is URL {
4746
convertible = serverUrlFileName as? URLConvertible
@@ -72,11 +71,9 @@ public extension NextcloudKit {
7271
options.queue.async { taskHandler(task) }
7372
}) .uploadProgress { progress in
7473
uploadedSize = progress.totalUnitCount
75-
uploadCompleted = progress.fractionCompleted == 1.0
7674
options.queue.async { progressHandler(progress) }
7775
} .responseData(queue: self.nkCommonInstance.backgroundQueue) { response in
7876
var ocId: String?, etag: String?, date: Date?
79-
var result: NKError
8077

8178
if self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields) != nil {
8279
ocId = self.nkCommonInstance.findHeader("oc-fileid", allHeaderFields: response.response?.allHeaderFields)
@@ -95,19 +92,14 @@ public extension NextcloudKit {
9592
date = dateRaw.parsedDate(using: "EEE, dd MMM y HH:mm:ss zzz")
9693
}
9794

98-
if !uploadCompleted {
99-
nkLog(error: "Upload incomplete: only \(uploadedSize) bytes sent.")
100-
result = .uploadIncomplete
101-
} else {
102-
result = self.evaluateResponse(response)
103-
}
104-
10595
options.queue.async {
106-
completionHandler(account, ocId, etag, date, uploadedSize, response.response?.allHeaderFields, result)
96+
completionHandler(account, ocId, etag, date, uploadedSize, response, self.evaluateResponse(response))
10797
}
10898
}
10999

110-
options.queue.async { requestHandler(request) }
100+
options.queue.async {
101+
requestHandler(request)
102+
}
111103
}
112104

113105
/// Asynchronously uploads a file to the Nextcloud server.
@@ -148,7 +140,7 @@ public extension NextcloudKit {
148140
etag: String?,
149141
date: Date?,
150142
size: Int64,
151-
headers: [AnyHashable: Any]?,
143+
response: AFDataResponse<Data>?,
152144
error: NKError
153145
) {
154146
await withCheckedContinuation { continuation in
@@ -161,14 +153,14 @@ public extension NextcloudKit {
161153
options: options,
162154
requestHandler: requestHandler,
163155
taskHandler: taskHandler,
164-
progressHandler: progressHandler) { account, ocId, etag, date, size, headers, error in
156+
progressHandler: progressHandler) { account, ocId, etag, date, size, response, error in
165157
continuation.resume(returning: (
166158
account: account,
167159
ocId: ocId,
168160
etag: etag,
169161
date: date,
170162
size: size,
171-
headers: headers,
163+
response: response,
172164
error: error
173165
))
174166
}
@@ -355,7 +347,7 @@ public extension NextcloudKit {
355347
}
356348

357349
guard uploadNKError == .success else {
358-
return completion(account, filesChunkOutput, nil, .errorChunkFileUpload)
350+
return completion(account, filesChunkOutput, nil, uploadNKError)
359351
}
360352

361353
// Assemble the chunks

Sources/NextcloudKit/NextcloudKit.swift

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -178,26 +178,36 @@ open class NextcloudKit {
178178
}
179179
#endif
180180

181-
/// Evaluates an Alamofire response and returns the appropriate NKError.
182-
/// Treats `inputDataNilOrZeroLength` as `.success`.
181+
/// Evaluates a generic Alamofire response into NKError with simple HTTP-aware rules.
182+
/// - Note:
183+
/// - Explicit cancellations return `.cancelled`.
184+
/// - Any HTTP 2xx is considered success, regardless of body presence.
185+
/// - If no HTTP status is available, fall back to Alamofire's `Result`.
183186
func evaluateResponse<Data>(_ response: AFDataResponse<Data>) -> NKError {
184-
if let afError = response.error?.asAFError {
185-
if afError.isExplicitlyCancelledError {
186-
return .cancelled
187-
}
187+
// 1) Cancellations take precedence
188+
if let afError = response.error?.asAFError,
189+
afError.isExplicitlyCancelledError {
190+
return .cancelled
188191
}
189192

190-
switch response.result {
191-
case .failure(let error):
192-
if let afError = error.asAFError,
193-
case .responseSerializationFailed(let reason) = afError,
194-
case .inputDataNilOrZeroLength = reason {
193+
// 2) Prefer HTTP status code when available
194+
if let code = response.response?.statusCode {
195+
if (200...299).contains(code) {
195196
return .success
196-
} else {
197-
return NKError(error: error, afResponse: response, responseData: response.data)
198197
}
198+
// Non-2xx: let the error flow below (even if serializer said "success")
199+
}
200+
201+
// 3) Fall back to Alamofire's result (covers transport errors and missing status)
202+
switch response.result {
199203
case .success:
200204
return .success
205+
206+
case .failure(let error):
207+
// No need to special-case inputDataNilOrZeroLength here:
208+
// - If it was a 2xx, we already returned above.
209+
// - If it's not 2xx or no status code, it's a real failure for our purposes.
210+
return NKError(error: error, afResponse: response, responseData: response.data)
201211
}
202212
}
203213
}

0 commit comments

Comments
 (0)