B4A Library Amazon S3 Library

Description: A class i wrote that simplifies the ability to perform PUT, GET, LIST and DELETE functions on amazon s3 cloud services.
Requirements: ByteConverter, DateUtils, Encryption, HTTP Library, Reflection, StringUtils
Optional: XOM

I made some modifications to the HttpJob class. I'll include a modified version in the example, but the following should be added to the class:
B4X:
Sub Class_Globals
...
        Private DownloadFolder As String
    Private DownloadFileName As String
End Sub
Public Sub FinishDownload
    File.Copy(HttpUtils2Service.TempFolder,taskId,DownloadFolder,DownloadFileName)
    File.DELETE(HttpUtils2Service.TempFolder,taskId)
End Sub
Public Sub SetDownloadsettings(InDownloadFolder As String, InDownloadFileName As String)
    DownloadFolder=InDownloadFolder
    DownloadFileName=InDownloadFileName
End Sub
Public Sub GetXMLResponse As InputStream
    Dim tr As TextReader,res As String,tempPosition As Int, tempstream As InputStream
    tr.Initialize2(File.OpenInput(HttpUtils2Service.TempFolder, taskId), "UTF8")
    res = tr.ReadAll
    tr.Close
    tempPosition=res.IndexOf("<ListBucketResult ")
    tempstream.InitializeFromBytesArray(res.GetBytes("UTF8"),tempPosition,res.Length-tempPosition)
    Return tempstream
End Sub

Public Sub DeleteRequest(Link As String)
    mLink = Link
    req.InitializeDelete(Link)
    CallSubDelayed2(HttpUtils2Service, "SubmitJob", Me)
End Sub

To use the module you'll want to create a map (used for passing your own custom headers. If you don't want to, just create a map and pass it uninitialized) and call one of the four functions:
awstest.AwsPUT
awstest.AwsGET
awstest.AwsDELETE
awstest.AwsLIST

There are 2 other functions to set info for the aws service:
awstest.OverrideBucketInfo - takes bucket name, apppath and remoteuserdir
awstest.OverrideAccessKeys - takes access key and secret key

I created two different types of methods to read in the response (really just needed for the LIST since it comes back in xml). One that parses it like a string and the other that treats it as XML and uses the XOM parser to get the correct elements.
They're in the main activity.

Some notes:
You can enter in your keys/bucket name/optional paths in the Class_Globals of awsAuthorization or if you're not comfortable doing that, you can always just leave them blank and use the Override functions to set them. In the initialize method i had a dim P phone, remoteUserDir=P.GetSettings("android_id"). The way i'm using this is to create a folder in the S3 bucket that's unique per device so I have have multiple devices using my app and uploading the results to a S3 bucket. That way i can create custom responses for the files they store.
There are some unused methods in the class because i was sort of confused with the different encryption methods amazon has for their REST api documentation.
If you require a different function for the REST api, send me a message and i can update the class. If you want to add something to the class, feel free to write me with the new code segment so i can add it. I only have 4 functions out of like 20 or so written here, so it can be expanded later.

Thank you to Erel, nicholas.jj.taylor, the rest of the contributors that allows me to do this.
 

Attachments

  • AndroidAmazonS3.zip
    10.8 KB · Views: 416

SpinBower

Member
Licensed User
Longtime User
Hi I am trying to use your sample program to upload files to my S3. I changed the the credentials with "awstest.overideaccesskeys("***","***")" but that still throws this error, I only edited the activity create sub, I added it below too. Thanks!

B4X:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><StringToSignBytes>50 55 54 0a 0a 0a 32 30 31 34 30 35 31 36 54 32 32 35 36 30 33 5a 0a 78 2d 61 6d 7a 2d 61 63 6c 3a 70 72 69 76 61 74 65 0a 78 2d 61 6d 7a 2d 63 6f 6e 74 65 6e 74 2d 73 68 61 32 35 36 3a 34 32 39 66 33 30 31 36 36 30 64 64 31 65 34 37 30 36 34 62 35 33 34 63 35 31 62 66 39 34 66 32 31 66 32 36 35 65 37 65 33 31 36 30 30 64 37 63 38 37 36 63 63 63 63 32 66 38 32 36 33 35 31 37 0a 2f 6c 6f 73 74 6d 6f 64 65 2f 2f 74 65 73 74 2e 74 78 74</StringToSignBytes><RequestId>FA60E64814892508</RequestId><HostId>uhDWPRjW/8Ide8bJMmTt/dttxcfHjUh1adlIQVHD4kwRwNaghZp2lgZkrxKM7Jw8g+ItrqxjgOI=</HostId><SignatureProvided>z8lC+UIwMMMI4AuT4z9GQ5a6xZg=</SignatureProvided><StringToSign>PUT
20140516T225603Z
x-amz-acl:private
x-amz-content-sha256:429f301660dd1e47064b534c51bf94f21f265e7e31600d7c876cccc2f8263517
/lostmode//test.txt</StringToSign><AWSAccessKeyId>*************</AWSAccessKeyId></Error>

B4X:
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    Dim InMap As Map
    InMap.Initialize
    InMap.Put("x-amz-acl","private")
    File.WriteString(File.DirInternal, "test.txt", "Yo This Is A Test!")
    Dim awstest As awsAuthorization
    awstest.Initialize
    awstest.OverrideAccessKeys("*********", "**********")
    awstest.OverrideBucketInfo("lostmode","","")
    awstest.AwsPUT(File.DirInternal,"test.txt","PutRequest",Me,InMap,"","")
    Activity.Finish
End Sub
 

hypergreatthing

Member
Licensed User
Longtime User
There's this concept of AppPath that kind of complicates things.
Try putting in something like awstest.OverrideBucketInfo("lostmode","test","")
I also had some errors in that version. I have since fixed them. I think it was mainly in the List and delete functions though having to do with not using the currentDir, but using the remoteDir when generating the authstring. I'll update that soon.

You can use http://www.string-functions.com/hex-string.aspx to convert the hex string to a normal string and compare it to aws is expecting.
B4X:
PUT

20140516T225603Z
x-amz-acl:private
x-amz-content-sha256:429f301660dd1e47064b534c51bf94f21f265e7e31600d7c876cccc2f8263517
/lostmode//test.txt
You had:
B4X:
PUT


20140516T225603Z
x-amz-acl:private
x-amz-content-sha256:429f301660dd1e47064b534c51bf94f21f265e7e31600d7c876cccc2f8263517
/lostmode//test.txt

I think the FileMimeType was missing. You can set it in the class module or pass it along as the last parameter in the put method.
awstest.AwsPUT(File.DirInternal,"test.txt","PutRequest",Me,InMap,"","text/plain")

While it's optional in aws, the code is creating an auth string like so:
B4X:
Dim StringToSign As String
  StringToSign=HTTPMethod & EOL
  StringToSign = StringToSign & EOL
  StringToSign = StringToSign & CurrentFileMimeType & EOL
  StringToSign = StringToSign & iso8601date & EOL
  StringToSign = StringToSign & CreateCanonicalHeaders(HeaderMap)

So if CurrentFileMimeType is set to "" it creates an extra carriage return.
Next version i'll also add a if (CurrentFileMimeType<>"") then ... so it won't add an extra return.
 

garciag

New Member
Licensed User
Longtime User
I'm having a difficult time getting this to work. I get an error back from amazon with "Signature Does Not Match". I was wondering if you have any updates to this library?

Thanks.
 
Top