diff --git a/Sources/Storage/Helpers.swift b/Sources/Storage/Helpers.swift new file mode 100644 index 00000000..3bbdf0d4 --- /dev/null +++ b/Sources/Storage/Helpers.swift @@ -0,0 +1,53 @@ +// +// Helpers.swift +// +// +// Created by Guilherme Souza on 22/05/24. +// + +import Foundation + +#if canImport(CoreServices) + import CoreServices +#endif + +#if canImport(UniformTypeIdentifiers) + import UniformTypeIdentifiers +#endif + +#if os(Linux) || os(Windows) + /// On Linux or Windows this method always returns `application/octet-stream`. + func mimeTypeForExtension(_: String) -> String { + "application/octet-stream" + } +#else + func mimeTypeForExtension(_ fileExtension: String) -> String { + if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, visionOS 1.0, *) { + return UTType(filenameExtension: fileExtension)?.preferredMIMEType ?? "application/octet-stream" + } else { + guard + let type = UTTypeCreatePreferredIdentifierForTag( + kUTTagClassFilenameExtension, + fileExtension as NSString, + nil + )?.takeUnretainedValue(), + let mimeType = UTTypeCopyPreferredTagWithClass( + type, + kUTTagClassMIMEType + )?.takeUnretainedValue() + else { return "application/octet-stream" } + + return mimeType as String + } + } +#endif + +extension String { + var pathExtension: String { + (self as NSString).pathExtension + } + + var fileName: String { + (self as NSString).lastPathComponent + } +} diff --git a/Sources/Storage/StorageFileApi.swift b/Sources/Storage/StorageFileApi.swift index efce0b56..402e6b83 100644 --- a/Sources/Storage/StorageFileApi.swift +++ b/Sources/Storage/StorageFileApi.swift @@ -38,14 +38,14 @@ public class StorageFileApi: StorageApi { file: Data, options: FileOptions ) async throws -> FileUploadResponse { - let contentType = options.contentType + let contentType = options.contentType ?? mimeTypeForExtension(path.pathExtension) var headers = HTTPHeaders([ "x-upsert": "\(options.upsert)", ]) headers["duplex"] = options.duplex - let fileName = fileName(fromPath: path) + let fileName = path.fileName let form = FormData() form.append( @@ -472,13 +472,13 @@ public class StorageFileApi: StorageApi { file: Data, options: FileOptions = FileOptions() ) async throws -> SignedURLUploadResponse { - let contentType = options.contentType + let contentType = options.contentType ?? mimeTypeForExtension(path.pathExtension) var headers = HTTPHeaders([ "x-upsert": "\(options.upsert)", ]) headers["duplex"] = options.duplex - let fileName = fileName(fromPath: path) + let fileName = path.fileName let form = FormData() form.append(file: File( @@ -509,7 +509,3 @@ public class StorageFileApi: StorageApi { return SignedURLUploadResponse(path: path, fullPath: fullPath) } } - -private func fileName(fromPath path: String) -> String { - (path as NSString).lastPathComponent -} diff --git a/Sources/Storage/Types.swift b/Sources/Storage/Types.swift index 0e887210..75bf7210 100644 --- a/Sources/Storage/Types.swift +++ b/Sources/Storage/Types.swift @@ -44,9 +44,8 @@ public struct FileOptions: Sendable { /// in the `Cache-Control: max-age=` header. Defaults to 3600 seconds. public var cacheControl: String - /// The `Content-Type` header value. Should be specified if using a `fileBody` that is neither - /// `Blob` nor `File` nor `FormData`, otherwise will default to `text/plain;charset=UTF-8`. - public var contentType: String + /// The `Content-Type` header value. + public var contentType: String? /// When upsert is set to true, the file is overwritten if it exists. When set to false, an error /// is thrown if the object already exists. Defaults to false. @@ -59,7 +58,7 @@ public struct FileOptions: Sendable { public init( cacheControl: String = "3600", - contentType: String = "text/plain;charset=UTF-8", + contentType: String? = nil, upsert: Bool = false, duplex: String? = nil ) {