Search code examples
vbamsxmlconfluence-rest-apimsxml2

How should I encode GIF file data in a multipart form using VBA MSXML2.XMLHTTP API?


I'm trying to use "Create Attachment" API in to Confluence: it "works" but the resulting file in confluence is not being served as an image: it just appears as text, so I believe the processing of the file data is failing: assuming because it's not encoded correctly.

I've tried multiple combinations of encoding for the data (base64, raw, unicode) and tried adding utf-8 in API header... I'm sort of clutching at straws: encoding gives me a headache. Between a) XMLHTTP send encoding (utf8 i guess?) b) VBA String encoding (utf16) and c) ADODB.Stream (utf-16 i think) I've really got very poor grasp on how they all interact. My best guess below is converting the ADODB.Stream string to utf-8. Leaving it "as is" doesn't work either. I can run the API in Postman and it works fine: but I've got no idea how Postman does it or how to replicate: code snippet just says "(data)" where the image data goes. Tried using "postman-inspector" as suggested by some but I didn't really get anywhere (as it guess it packages the data in to some other form then the postman server does the actual send: who knows what it's sending).

For example: this tiny gif file: my requestData (for MSXML2.XMLHTTP.send) looks like this:

------IMabOUnDdfdfAaAAAA
Content-Disposition: form-data; name="file" ; filename="ttmRecordTypeImage19.gif"
Content-Type: image/gif

GIF89a  "  !ù   ,      ‚ÿÿÿ™f ÌÌ™ÿÌÌÿÌ™         2XºÜþ/È)a8Ww3žÜ@i¡G6¡®jÀ  ”¿BmÏ(ãLp߮ܯìÅ(¤’  ;
------IMabOUnDdfdfAaAAAA
Content-Disposition: form-data; name="minorEdit"

true
------IMabOUnDdfdfAaAAAA--

I'm building that requestdata in to a string, with the "GIF Data Bit" coming from this function (have tried with or without strconv):

Function ReadFileEncoded(filePath As String) As String
    Dim fileStream As Object
    Set fileStream = CreateObject("ADODB.Stream")
    fileStream.Type = 1 ' Binary mode
    fileStream.Open
    fileStream.LoadFromFile filePath
    
    ReadFileEncoded = StrConv(fileStream.Read(), vbUnicode)
    
    fileStream.Close
    Set fileStream = Nothing
End Function

My API header looks like this:

    http.setRequestHeader "Authorization", GetAuth
    http.setRequestHeader "X-Atlassian-Token", "nocheck"
    http.setRequestHeader "Content-Type", "multipart/form-data;  boundary=" & BOUNDARY

If someone could suggest maybe a methodical way I could approach the problem: my "best result" includes the "GIF89" bit at the start so I assume that's a good sign? But looking in hex editor between original file and the one generated, it falls apart after character 15... I'm thinking I make a huge logic table of 30 combinations of encoding and decoding at various stages to various strings and objects but that might drive me insane.

I've read a few similar questions saying to use strconv(..vbFromUnicode) for the request data... Tried that with or without using strconv(...vbUnicode) on the file data first. Thanks for your help.


Solution

  • Apologies I found the answer in the post below: encapsulating the entire thing in an ADODB stream, including reading the "string bits" in to a byte array. Not sure etiquette for sighting a different post as an answer?

    Anyway this is the "magic":

        With obStream
            .Type = 1 'binary
            .Open
            .LoadFromFile stFile
            .Position = 0
            vrImage = .Read
            .Close
                
            ' combine part, image , end
            .Open
            .Position = 0
            .Type = 1 ' binary
            .Write ToBytes(stFirstBit)
            .Write vrImage
            .Write ToBytes(stSecondBit)
            .Position = 0
        End With
    

    Upload file to file.io using POST method