Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Swift generated code for multipart/form-data - video upload does not work from device/simulator #10139

Open
1 task done
outwrq opened this issue Jul 22, 2021 · 4 comments
Open
1 task done

Comments

@outwrq
Copy link

outwrq commented Jul 22, 2021

Is there an existing issue for this?

  • I have searched the existing issues

Describe the Issue

Uploading a video using the generated code via device/simulator causes a nil value to be hit at this line (in the conversion from data to string):

let fileContent = String(data: fileData, encoding: .utf8)!

It seems like the fileData being converted to a string so it can be passed in the multipartform does not work.

Using the postman platform to interact with my API works seamlessly. The video uploads from the desktop to the server fine however the error persists when sending requests off device/sim using the generated code.

Trialled (to no avail):

  • Converting video from native .MOV to .mp4
  • Converting the Data/NSData with different encoding strategies - eg UT8.self (let fileContent = String(decoding: fileData, as: UTF8.self)
  • All other methods on stackoverflow/google etc

Is there an alternative code block that can be used in swift to send video data as part of the multipart/form-data request?
Thanks

Steps To Reproduce

  1. Use the generated code snippet from iOS device or simulator to upload a chosen video.
  2. Observe the nil value being hit and bytes being shown in the console.

Screenshots or Videos

Environment Information

- Operating System: macOS Big Sur 11.4
- Platform Type: Native App
- Postman Version: 8.8.0

Additional Context?

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

var semaphore = DispatchSemaphore (value: 0)

let parameters = [
 [
  "key": "video",
  "src": "source_file_path",
  "type": "file"
 ]] as [[String : Any]]

let boundary = "Boundary-\(UUID().uuidString)"
var body = ""
var error: Error? = nil
for param in parameters {
 if param["disabled"] == nil {
  let paramName = param["key"]!
  body += "--\(boundary)\r\n"
  body += "Content-Disposition:form-data; name=\"\(paramName)\""
  if param["contentType"] != nil {
   body += "\r\nContent-Type: \(param["contentType"] as! String)"
  }
  let paramType = param["type"] as! String
  if paramType == "text" {
   let paramValue = param["value"] as! String
   body += "\r\n\r\n\(paramValue)\r\n"
  } else {
   let paramSrc = param["src"] as! String
   let fileData = try NSData(contentsOfFile:paramSrc, options:[]) as Data
   let fileContent = String(data: fileData, encoding: .utf8)!
   body += "; filename=\"\(paramSrc)\"\r\n"
     + "Content-Type: \"content-type header\"\r\n\r\n\(fileContent)\r\n"
  }
 }
}
body += "--\(boundary)--\r\n";
let postData = body.data(using: .utf8)

var request = URLRequest(url: URL(string: "upload_url")!,timeoutInterval: Double.infinity)
request.addValue("token xxxx", forHTTPHeaderField: "Authorization")
request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

request.httpMethod = "POST"
request.httpBody = postData

let task = URLSession.shared.dataTask(with: request) { data, response, error in 
 guard let data = data else {
  print(String(describing: error))
  semaphore.signal()
  return
 }
 print(String(data: data, encoding: .utf8)!)
 semaphore.signal()
}

task.resume()
semaphore.wait()
@outwrq
Copy link
Author

outwrq commented Aug 8, 2021

Has there been any movement on this? Still yet to find a solution to resolve

@akshaydeo
Copy link

@outwrq, thank you for reporting this issue. We are actively looking into this, and I will update this ticket as soon as we have a fix ready to be tested.

@aman-v-singh
Copy link

aman-v-singh commented Jul 6, 2023

Hey @outwrq,
Thank you for reporting this issue, the fix for this issue is underway and will be available with the upcoming release, until then you can refer to this solution to solve your issue.
Regards

@aman-v-singh
Copy link

@outwrq Newly generated code for your usecase is:-

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

let parameters = [
    [
        "key": "VideoFile",
        "src": "{VIDEO_FILE_PATH}",
        "type": "file"
    ]] as [[String: Any]]

let boundary = "Boundary-\(UUID().uuidString)"
var body = Data()
var error: Error? = nil
for param in parameters {
    if param["disabled"] != nil { continue }
    let paramName = param["key"]!
    body += Data("--\(boundary)\r\n".utf8)
    body += Data("Content-Disposition:form-data; name=\"\(paramName)\"".utf8)
    if param["contentType"] != nil {
        body += Data("\r\nContent-Type: \(param["contentType"] as! String)".utf8)
    }
    let paramType = param["type"] as! String
    if paramType == "text" {
        let paramValue = param["value"] as! String
        body += Data("\r\n\r\n\(paramValue)\r\n".utf8)
    } else {
        let paramSrc = param["src"] as! String
        let fileURL = URL(fileURLWithPath: paramSrc)
        if let fileContent = try? Data(contentsOf: fileURL) {
            body += Data("; filename=\"\(paramSrc)\"\r\n".utf8)
            body += Data("Content-Type: \"content-type header\"\r\n".utf8)
            body += Data("\r\n".utf8)
            body += fileContent
            body += Data("\r\n".utf8)
        }
    }
}
body += Data("--\(boundary)--\r\n".utf8);
let postData = body


var request = URLRequest(url: URL(string: "https://postman-echo.com/post")!,timeoutInterval: Double.infinity)
request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

request.httpMethod = "POST"
request.httpBody = postData

let task = URLSession.shared.dataTask(with: request) { data, response, error in 
    guard let data = data else {
        print(String(describing: error))
        exit(EXIT_SUCCESS)
    }
    print(String(data: data, encoding: .utf8)!)
    exit(EXIT_SUCCESS)
}

task.resume()
dispatchMain()

Please try to use it and check if your problem is solved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants