Uploading an image as form data (to Facebook)

Hello,

I’ve been struggling with network.request / network.upload recently, trying to upload an image to the Facebook Graph API.

The request format they want is a multipart/form-data thing, containing both the file, and the access token.

The way network.upload and network.request currently work don’t do this at all, but the problem is I can’t find how to just make my own request and send the image as post data as it should be sent.

Here is how a “correct” request sent from curl looks like:

--------------------------9785bf8f76bfd3dd

Content-Disposition: form-data; name=“file”; filename=“Icon-60.png”

Content-Type: image/png

PNG

IHDR<<µN%tEXtSoftwareAdobe ImageReadyqÉe<mBiTXtXML:com.adobe.xmp<?xpacket begin=“” id=“W5M0MpCehiHzreSzNTczkc9d”?> <x:xmpmeta xmlns:x=“adobe:ns:meta/” x:xmptk=“Adobe XMP Core 5.6-c014 79.156797, 2014/08/20-09:53:02        “> <rdf:RDF xmlns:rdf=“http://www.w3.org/1999/02/22-rdf-syntax-ns#”> <rdf:Description rdf:about=”” xmlns:xmp=“http://ns.adobe.com/xap/1.0/” xmlns:dc=“http://purl.org/dc/elements/1.1/” xmlns:photoshop=“http://ns.adobe.com/photoshop/1.0/” xmlns:xmpMM=“http://ns.adobe.com/xap/1.0/mm/” xmlns:stEvt="http://ns.adobe.com/xap/

[…] (I cut the image part since it’s long)

KÜ(ÚÜÄk~@ïXS]ÕÓeôĬ_=k¢MÒ}੪6½e±\ZimõH%ßug84úU÷ÊÝYö»îyH?GੲUÎt¤:g±¦,f?ôí«·¼þá(vqpïñbóc?zOý

9Øñ6³çlÎÄÆFå¥iMLQ&êIõøÊÄÉ»µÐp/¹¡I çét÷QË4IÖ$H ¾~åÀ~mZûÒ\XÑòEwº ³¹É³â?ÁËàXyRÂ"Û.4v·#ùÛéëo~ôÌH"±ýrÉÓ4þêk®Ìµý¬··«Ñîi|OApsß|,ä²v'óÉ/C!·ÿ¿,Eüh÷IEND®B

--------------------------9785bf8f76bfd3dd

Content-Disposition: form-data; name=“access_token”

CAACEdEose0cBA[…]

--------------------------9785bf8f76bfd3dd–

If I add an image to network.upload as stated in the documentation, it will just upload it and can’t add other parameters, so that doesn’t work.

I tried the solutions proposed here, mostly consisting of reading the file and encoding it myself, but it never works. I use a network inspecter to see the request results, and if I just read the file content and send it, the request is just empty. When I encode the image in base64, it is sent, but that’s not what Facebook want.

So I think what I need is just a way to write the content of the request entirely, and to have the image in the correct format. But I’m getting lost here.

Code:

utils.uploadImage = function( filename, dir, url, onComplete, formParams) local function \_b64enc( data ) -- character table string local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' return ( (data:gsub( '.', function( x ) local r,b='', x:byte() for i=8,1,-1 do r=r .. ( b % 2 ^ i - b % 2 ^ ( i - 1 ) \> 0 and '1' or '0' ) end return r; end ) ..'0000' ):gsub( '%d%d%d?%d?%d?%d?', function( x ) if ( #x \< 6 ) then return '' end local c = 0 for i = 1, 6 do c = c + ( x:sub( i, i ) == '1' and 2 ^ ( 6 - i ) or 0 ) end return b:sub( c+1, c+1 ) end) .. ( { '', '==', '=' } )[#data %3 + 1] ) end local path = system.pathForFile(filename, dir) local file, errStr = io.open( path, "rb" ) if file then log("IMGUPLOAD", "Launching upload " .. json.encode(formParams)) local content = file:read( "\*a" ) local img = content log("IMGUPLOAD", "Launching upload " .. tostring(img)) local headers = {} headers["Content-Type"] = "multipart/form-data" -- local body = "file=" .. img -- for key, value in pairs(formParams) do -- body = body.. "&" .. key .. "=" .. value -- end local params = {} params.headers = headers params.body = img params.progress = "upload" -- params.body = { -- filename = filename, -- baseDirectory = dir -- } log("IMGUPLOAD", "Launch request " .. json.encode(params)) network.request(url, "POST", onComplete, params) end end

I tried tons of variations of this code, but I just can’t send what I want.