xhr POST to AWS S3
This weekend, I tried to implement the AWS Simple Storage Service (s3) "POST object" method to put files in S3.
Posting to S3 requires you to submit an HTML form. It was designed for directly uploading files from a browser to S3 without having to go through an intermediate application server. This use case would apply well to Mobile apps, but it seems that it may not work for the Titanium HTTP client.
The problem is that in a web form, you most browsers prevent setting a value for a <INPUT type="file" name="file" value="{path/filename}>
. (It's a very important browser security precaution to prevent web pages from silently nabbing local files.) Consequently, it appears that the file never gets uploaded with the POST action, and S3 responds with an inappropriate "specified method not allowed" error. (I posted from a browser to determine it really was.)
So the question is: Can Titanium programatically POST a file as part of a web form without ever presenting the form to the end user?
Note A related Q&A item falls short of providing an actual answer.
4 Answers
-
Ted is right, you cannot POST, but you can use a REST PUT. I have just posted a question about getting this working for Android, but if you or anybody else would like the source code, I've posted it as a pastie at the bottom of my question.
Any help getting the code to also work on Android would be appreciated.
-
I'm inclined to say Titanium can't.
However, there's a decent workaround. Create your own server-side script that accepts data from your Titanium app, then simply add the additional parameters you need and complete the POST to the S3 (in PHP, you could use
curl
, for example).Yes, it's a redundant step, but it should still be fast, and may be your only option. Good luck! :)
-
Yep, you need to do the upload to S3 on the server-side. But that’s not too tricky if you use the new & official PHP-framework by AWS (formerly Cloudfusion).
-
The basic answer is, "No. The AWS S3 POST API was designed for direct-from-browser html form upload."
However, you do not need to upload to your own web application first and then send the file from the web server to S3 (which incurs bandwidth costs). You can still upload directly to S3 using a PUT with their REST API.
Doing this securely requires that you off-load the AWS authentication step from your Titanium app. As pointed out in another thread, storing your AWS secret access key in your app leaves it vulnerable to hackers. So, to use the S3 PUT API, I implemented a "signing service" that my Ti app could call to sign each PUT action.
The resulting workflow goes something like this:
- The app has a picture to send to AWS, so it uses xhr to send the target "key" (path on AWS) to my signing service (along with any other necessary parameters.
- The signing service uses the path and parameters to assemble a "String to Sign" (AWS's term), and hashes it using my AWS secret key.
- The signing service responds to the Ti app's request with a JSON document containing the authorization and the date string it used in the string to sign.
- The Ti app inserts the date and authorization as headers into a new xhr instance, and then PUTs the file onto S3.
That's all it took. There is still a minor vulnerability doing it this way: someone could crack the app, learn about the signing service, and then start calling it for their own nefarious purposes. However, although they could upload, they could not access the files they upload–the signing service signs only for a simple PUT call.