1 // Copyright 2023-present 650 Industries. All rights reserved.
2 
3 import CoreServices
4 import ExpoModulesCore
5 
findMimeTypenull6 func findMimeType(forAttachment attachment: URL) -> String {
7   if let identifier = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, attachment.pathExtension as CFString, nil)?.takeRetainedValue() {
8     if let type = UTTypeCopyPreferredTagWithClass(identifier, kUTTagClassMIMEType)?.takeRetainedValue() {
9       return type as String
10     }
11   }
12   return "application/octet-stream"
13 }
14 
createUrlSessionnull15 func createUrlSession(type: SessionType, delegate: URLSessionDelegate) -> URLSession {
16   let configuration = type == .foreground ? URLSessionConfiguration.default : URLSessionConfiguration.background(withIdentifier: UUID().uuidString)
17   configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
18   configuration.urlCache = nil
19   return URLSession(configuration: configuration, delegate: delegate, delegateQueue: .main)
20 }
21 
createUrlRequestnull22 func createUrlRequest(url: URL, headers: [String: String]?) -> URLRequest {
23   var request = URLRequest(url: url)
24 
25   if let headers {
26     for (key, value) in headers {
27       request.setValue(value, forHTTPHeaderField: key)
28     }
29   }
30   return request
31 }
32 
createUploadTasknull33 func createUploadTask(session: URLSession, targetUrl: URL, sourceUrl: URL, options: UploadOptions) -> URLSessionUploadTask {
34   var request = createUrlRequest(url: targetUrl, headers: options.headers)
35 
36   switch options.uploadType {
37   case .binaryContent:
38     return session.uploadTask(with: request, fromFile: sourceUrl)
39   case .multipart:
40     let boundaryString = UUID().uuidString
41     let data = try? createMultipartBody(boundary: boundaryString, sourceUrl: sourceUrl, options: options)
42 
43     request.setValue("multipart/form-data; boundary=\(boundaryString)", forHTTPHeaderField: "Content-Type")
44     request.httpBody = data
45 
46     return session.uploadTask(withStreamedRequest: request)
47   }
48 }
49 
createMultipartBodynull50 func createMultipartBody(boundary: String, sourceUrl: URL, options: UploadOptions) throws -> Data {
51   let fileName = options.fieldName ?? sourceUrl.lastPathComponent
52   let fileContents = try String(contentsOf: sourceUrl)
53   let mimeType = options.mimeType ?? findMimeType(forAttachment: sourceUrl)
54 
55   let body = """
56 \(headersForMultipartParams(options.parameters, boundary: boundary))
57 --\(boundary)
58 Content-Disposition: form-data; name="\(fileName)"; filename="\(sourceUrl.lastPathComponent)"
59 Content-Type: \(mimeType)
60 
61 \(fileContents)
62 --\(boundary)--
63 """
64 
65   guard let bodyData = body.data(using: .utf8) else {
66     throw HeaderEncodingFailedException(sourceUrl.absoluteString)
67   }
68   return bodyData
69 }
70 
headersForMultipartParamsnull71 func headersForMultipartParams(_ params: [String: String]?, boundary: String) -> String {
72   guard let params else {
73     return ""
74   }
75   return params.map { (key: String, value: String) in
76 """
77 --\(boundary)
78 Content-Disposition: form-data; name="\(key)"
79 
80 \(value)
81 """
82   }
83   .joined()
84 }
85