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