I have a backend for my Swift app that was designed by someone else. It is written in Python and uses FastAPI. There is an API call that changes user's profile photo. In that request, I am supposed to send in a png as mutlipart/form-data. But I always get an error message saying that the image type is not supported.
["reason": Image Type Unsupported, "message": Bad Request]
Last night, I was debugging and figured I should check the hexdump of the file that is being uploaded to the server. So, instead of verifying that the file is png, I just saved it in a temporary folder on my server. I downloaded the file from my server and turns out, the first three bytes of the image are "ef bf bd", which stands for BOM UTF-8, I believe. PNG's are supposed to begin with "89 50 4e". There are many differences in the actual png I send vs. what the server receives so the file is getting encoded somehow and I have no idea why. Here's my code for it:
// photo is a UIImage variable
let pngData = photo.pngData()!
// generate boundary string using a unique per-app string
let boundary = UUID().uuidString
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "PUT"
// Set Content-Type Header to multipart/form-data, this is equivalent to submitting form data with file upload in a web browser
// And the boundary is also set here
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Accept")
urlRequest.addValue(tokens.idToken, forHTTPHeaderField: "Authorization")
var data = Data()
// Add the opening boundary
data.append("--\(boundary)\r\n".data(using: .utf8)!)
data.append("Content-Disposition: form-data; name=\"file\"; filename=\"user_icon.png\"\r\n".data(using: .utf8)!)
data.append("Content-Type: image/png\r\n\r\n".data(using: .utf8)!)
// Add the PNG file data
data.append(pngData)
// Add the closing boundary
data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
let hex = data.reduce("") { $0 + String(format: "%02x", $1) }
print(hex)
// Send a PUT request to the URL, with the data we created earlier
session.uploadTask(with: urlRequest, from: data, completionHandler: { responseData, response, error in
if error == nil {
let jsonData = try? JSONSerialization.jsonObject(with: responseData!, options: .allowFragments)
if let json = jsonData as? [String: Any] {
print(json)
}
}
}).resume()
Any help would be greatly appreciated. I have been stuck on this problem for days.
- I have verified that the file that I am uploading is not a corrupted png file.
- I have tried commenting out the line with header "Accept".
- I have tried first getting the jpeg data and then converting that to png data.
- I looked at the hex of the file being uploaded (variable "hex"). That hex looks exactly like I would expect: boundary, the Content-Disposition, the Content-Type, and then the PNG data which starts with "89 50 4e"