Sending a file with URLConnection using CURL and PUT

I am having trouble figuring out how to PUT a file to an API with CURL using a URLConnection. I have several API methods working using GET,POST and DELETE. But I am stuck on everything that involves PUT and uploading a file.
This is the CURL that I’m having trouble with:

Var f As FolderItem
f = New FolderItem(“E:\Xojo Projects 2023\images\Xnavigator\XwindowsOrb256 - Copy.png”, FolderItem.PathModes.Native)
Var json As New JSONItem

winMain.URLConnection1.RequestHeader(“Authorization”) = "Bearer " + auth_token
winMain.URLConnection1.SetRequestContent(json.ToString, “application/json”)
winMain.URLConnection1.SetRequestContent(f.NativePath, “multipart/form-data”)
winMain.URLConnection1.Send(“PUT”, baseURLRest + “settings/avatarFile”)

This is what it returns. The API is REST v1.0:
{
“error”: “file_not_allowed”,
“error_code”: 28
}

This is the only documentation provided for the API.

Just for the record, Here is an example of some POST CURL for submitting a form that I have working great but doesn’t involve sending a file. Sharing only to show how I’m trying to do this.

Var json As New JSONItem
winMain.URLConnection1.RequestHeader(“Authorization”) = "Bearer " + auth_token
winMain.URLConnection1.SetRequestContent(json.ToString, “application/json”)
Var parameters As String = “”
parameters = parameters + “link=” + EncodeURLComponent(“https://example.com/avideolink.html”)
parameters = parameters + “&password=” + “”
parameters = parameters + “&remote=” + “0”
winMain.URLConnection1.SetRequestContent(parameters, “application/x-www-form-urlencoded”)
winMain.URLConnection1.Send(“POST”, baseURLRest + “dosomethingwith/link”)

Typically, a PUT tells the server to store the included entity at the given path. You would not use multiport with PUT. Read the contents of the folderitem, then use SetRequestContent to those contents with the correct content type. So if the file were a PNG, you would use image/png. The API might let you get away with application/octet-stream, which basically means “it could be anything.”

Also, you only ever need one SetRequestContent per request. The second call will replace the contents set in the first.

3 Likes

Thanks. I noticed I had two SetRequestContent’s in there as I was sitting here studying my code and was waiting for someone to say something :smiley: That was me trying anything and everything to get it to work as I got frustrated. I’ll give those suggestions a try and will post the results.

This is what I changed the code to and I get the exact same results/error:

Var f As FolderItem
f = New FolderItem(“E:\Xojo Projects 2023\images\Xnavigator\XwindowsOrb256 - Copy.png”, FolderItem.PathModes.Native)

winMain.URLConnection1.RequestHeader(“Authorization”) = "Bearer " + auth_token
winMain.URLConnection1.SetRequestContent(f.NativePath, “image/png”)
winMain.URLConnection1.Send(“PUT”, baseURLRest + “settings/avatarFile”)

Returns:
{
“error”: “file_not_allowed”,
“error_code”: 28
}

I feel like my problem may be in SetRequestContent(f.NativePath, “image/png”)

It seems like instead of a file path I should be sending the actual data of the file. So I’m missing something.

You’re sending the path of the file, not the file itself. Open the file with TextInputStream to get the contents.

Var Stream As TextInputStream = TextInputStream.Open(f)
Var FileContents As String = Stream.ReadAll()
Stream.Close

winMain.URLConnection1.SetRequestContent(FileContents, "image/png")
1 Like

I thought it might be something like that. You’re faster than me :slight_smile: That got me further. Now I’m getting:
Content:
{
“error”: “image_resolution_error”,
“error_code”: 32
}

However, I think I can figure it out from here. Thanks for the help!

All good now. I just need to add code to resize my image before I send, which I can do no problem.

Here is the working code for now. Thanks again for the help!

Var f As FolderItem
f = New FolderItem(“E:\Xojo Projects 2023\images\Xnavigator\XwindowsOrb128.png”, FolderItem.PathModes.Native)

Var Stream As TextInputStream = TextInputStream.Open(f)
Var FileContents As String = Stream.ReadAll()
Stream.Close

winMain.URLConnection1.RequestHeader(“Authorization”) = "Bearer " + auth_token
winMain.URLConnection1.SetRequestContent(FileContents, “image/png”)
winMain.URLConnection1.Send(“PUT”, baseURLRest + “settings/avatarFile”)