I have a mobile Android client that exchanges model objects with a Rails endpoint. I need to transfer media files back and forth as models' attributes. Apparently I need to send them as multipart/form-data, but I can't get this to work. I've tried this:
params.contentType = "multipart/form-data" params.data = model.toParams() ... xhr.open(type, params.url) # Add request headers etc. xhr.setRequestHeader('Content-Type', params.contentType) xhr.setRequestHeader("Connection", "close"); params.beforeSend(xhr) if params.beforeSend # Make the request xhr.send(params.data)
toParams() is a method used to normalize the model's attributes to a Rails-friendly format, taken from here.
I can see that the HTTPClient actually sends the request as multipart, but the problem is that I have no way of knowing what the boundary is, so I can't specify it in the Content-Type header. Because of this, when parsing the request, Rack thinks it's actually a URL encoded form and throws an invalid %-encoding exception when trying to handle the POST body as an escaped string.
I've also tried to build the request body manually:
b = "B0undary" data = "--#{b}" buffer = Ti.createBuffer(value: "") params.contentType = "multipart/form-data; boundary=#{b}" for k,v of model.toParams() data += "\r\nContent-Disposition: form-data; name=\"#{k}\"" if "#{v}" == "[object TiBlob]" data += "; filename=\"#{v.file.name}\"" if v.file data += "\r\nContent-Type: #{v.mimeType}\r\n" raw = Ti.Stream.createStream(source: v, mode: Ti.Stream.MODE_READ) buffer.append Ti.createBuffer(value: data) content = Ti.Stream.readAll(raw) buffer.append content data = "\r\n--#{b}" else data += "\r\n\r\n#{v}\r\n--#{b}" data += "--\r\n" buffer.append Ti.createBuffer(value: data) params.data = bufferThis way the request is parsed OK, but the file is corrupted (it's about twice the size of the original and has all the binary data messed up, though string data (e.g. timestamp) is intact).
I couldn't find an acceptable solution to this. Omitting the Content-Type header does not help either.
2 Answers
Don't set any headers that you don't need to. Ti does it automagically for you, on Android.
From my code:
var xhr = Titanium.Network.createHTTPClient(); xhr.open('POST',thisURL); if (MediaAPI.os !== 'android') { xhr.setRequestHeader("enctype", "multipart/form-data"); } xhr.send({file:myFileObject,data:someOtherData);
Turned out my second code snippet actually works if I do params.data = buffer.toBlob()
Your Answer
Think you can help? Login to answer this question!