StorageUtils.swift 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // Copyright 2022 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import Foundation
  15. #if os(iOS) || os(tvOS)
  16. import MobileCoreServices
  17. #elseif os(macOS) || os(watchOS)
  18. import CoreServices
  19. #endif // os(iOS) || os(tvOS)
  20. // swift(>=5.9) implies Xcode 15+
  21. // Need to have this Swift version check to use os(visionOS) macro, VisionOS support.
  22. // TODO: Remove this check and add `os(visionOS)` to the `os(iOS) || os(tvOS)` conditional above
  23. // when Xcode 15 is the minimum supported by Firebase.
  24. #if swift(>=5.9)
  25. #if os(visionOS)
  26. import MobileCoreServices
  27. #endif // os(visionOS)
  28. #endif // swift(>=5.9)
  29. class StorageUtils {
  30. internal class func defaultRequestForReference(reference: StorageReference,
  31. queryParams: [String: String]? = nil)
  32. -> URLRequest {
  33. var components = URLComponents()
  34. components.scheme = reference.storage.scheme
  35. components.host = reference.storage.host
  36. components.port = reference.storage.port
  37. if let queryParams = queryParams {
  38. var queryItems = [URLQueryItem]()
  39. for (key, value) in queryParams {
  40. queryItems.append(URLQueryItem(name: key, value: value))
  41. }
  42. components.queryItems = queryItems
  43. // NSURLComponents does not encode "+" as "%2B". This is however required by our backend, as
  44. // it treats "+" as a shorthand encoding for spaces. See also
  45. // https://stackoverflow.com/questions/31577188/how-to-encode-into-2b-with-nsurlcomponents
  46. components.percentEncodedQuery = components.percentEncodedQuery?.replacingOccurrences(
  47. of: "+",
  48. with: "%2B"
  49. )
  50. }
  51. let encodedPath = encodedURL(for: reference.path)
  52. components.percentEncodedPath = encodedPath
  53. guard let url = components.url else {
  54. fatalError("FirebaseStorage Internal Error: Failed to create url for \(reference.bucket)")
  55. }
  56. return URLRequest(url: url)
  57. }
  58. internal class func encodedURL(for path: StoragePath) -> String {
  59. let bucketString = "/b/\(GCSEscapedString(path.bucket))"
  60. var objectString: String
  61. if let objectName = path.object {
  62. objectString = "/o/\(GCSEscapedString(objectName))"
  63. } else {
  64. objectString = "/o"
  65. }
  66. return "/v0\(bucketString)\(objectString)"
  67. }
  68. internal class func GCSEscapedString(_ string: String) -> String {
  69. // This is the list at https://cloud.google.com/storage/docs/json_api/ without &, ; and +.
  70. let allowedSet =
  71. CharacterSet(
  72. charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$'()*,=:@"
  73. )
  74. return string.addingPercentEncoding(withAllowedCharacters: allowedSet)!
  75. }
  76. internal class func MIMETypeForExtension(_ fileExtension: String?) -> String {
  77. guard let fileExtension = fileExtension else {
  78. return "application/octet-stream"
  79. }
  80. if let type = UTTypeCreatePreferredIdentifierForTag(
  81. kUTTagClassFilenameExtension,
  82. fileExtension as NSString,
  83. nil
  84. )?.takeRetainedValue() {
  85. if let mimeType = UTTypeCopyPreferredTagWithClass(type, kUTTagClassMIMEType)?
  86. .takeRetainedValue() {
  87. return mimeType as String
  88. }
  89. }
  90. return "application/octet-stream"
  91. }
  92. }