I'm using AWS Lambda to create a simple upload service for my mobile product.
On the server, I generate a presigned URL using the following code
var params = {
Bucket: targetS3Bucket,
Key: key,
Body: '',
ContentType: event.contentType,
Expires: 60
};
s3.getSignedUrl('putObject', params, function (err, url){
context.done(null, {
'oneTimeUploadUrl': url,
'resultUrl': urlPrefix + key
});
});
Where targetS3Bucket
is a path to a folder on S3, key
is the name of the file itself and urlPrefix
is the root of the HTTP location of the file on S3 (ie: s3.amazonaws.com/some-folder/
)
Using this code with a built-in HTTP library (That is to say, NOT using any aws SDK) works without failure on PC and iOS, but not on Android.
The most recent version of the Android client code looks like this:
uri = new URL(oneTimeUploadUrl);
// Setup Connection
HttpsURLConnection http = (HttpsURLConnection) uri.openConnection();
http.setDoOutput(true);
http.setRequestMethod("PUT");
// Write Data
OutputStream os = http.getOutputStream();
os.write(_bytes);
os.flush();
os.close(); // request gets sent off to the server
This consistently fails with code 400
. I've tried several things like changing the encoding, using the non-https version of HttpsURLConnection
and a few other things, but to no avail.
I'd prefer to avoid bringing in the AWS SDK since I only need this single function to work, and using this lambada-side solution has made that possible on all platforms except android.
Here is the XML returned from AWS. The message that is returned is confusing because the client never alters the token, and the same process succeeds on other devices.
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>InvalidToken</Code>
<Message>The provided token is malformed or otherwise invalid.</Message>
<Token-0>{Token-0}</Token-0>
<RequestId>{RequestId}</RequestId>
<HostId>{HostId}</HostId>
</Error>