@Johann
If you want clients upload file to s3 directly, you can sign a URL for clients to upload a file. I use this way in a project to make app upload/delete/update files directly.
You can read:
Signing and Authenticating REST Requests
PUT Object(s3 restful api for uploading)
How boto library generate a signature
@Hermann Yung
You can use the restful APIs of s3 directly(and the SDK which provided by amazon for developer also use this), make an asynchronous http request is very easy. (I use this way in tornado and nginx)
--
You received this message because you are subscribed to the Google Groups "Tornado Web Server" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python-tornad...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
My code to sign s3 request.
The sign_s3_request
function is from S3 using python-requests.
import hmac
from hashlib import sha1
from base64 import encodebytes as encodestring
from email.utils import formatdate
from libs.utils import remove_blank
def sign_s3upload_request(
aws_access_key, aws_secret_key, bucket, name, mime_type
):
return sign_s3_request(
aws_access_key,
aws_secret_key,
bucket,
name,
{
'Content-Type': mime_type,
'x-amz-acl': 'bucket-owner-full-control'
},
'PUT'
)
def sign_s3download_request(
aws_access_key, aws_secret_key, bucket, name
):
return sign_s3_request(
aws_access_key,
aws_secret_key,
bucket,
name,
{
},
'GET'
)
def sign_s3delete_request(
aws_access_key, aws_secret_key, bucket, name
):
return sign_s3_request(
aws_access_key,
aws_secret_key,
bucket,
name,
{
#"Content-Length": '0',
#"Content-Type": 'text/plain'
},
'DELETE'
)
def sign_s3_request(
access_key, secret_key, bucket, objectkey,
headers, method, **kwargs
):
special_params = [
'acl', 'location', 'logging', 'partNumber', 'policy', 'requestPayment',
'torrent', 'versioning', 'versionId', 'versions', 'website', 'uploads',
'uploadId', 'response-content-type', 'response-content-language',
'response-expires', 'response-cache-control', 'delete', 'lifecycle',
'response-content-disposition', 'response-content-encoding'
]
interesting_headers = {
'content-md5': '',
'content-type': '',
'x-amz-date': formatdate(
timeval=None,
localtime=False,
usegmt=True
)
}
# get canonical string
for key in headers:
key_lower = key.lower()
if (
headers[key] and
(
key_lower in interesting_headers.keys() or
key_lower.startswith('x-amz-')
)
):
interesting_headers[key_lower] = headers[key].strip()
canonical_string = '%s\n' % method
for key in sorted(interesting_headers.keys()):
val = interesting_headers[key]
if not key.startswith('x-amz-'):
canonical_string += '%s\n' % val
canonical_string += '\n'
for key in sorted(interesting_headers.keys()):
val = interesting_headers[key]
if key.startswith('x-amz-'):
canonical_string += '%s:%s\n' % (key, val)
canonical_string += '/%s' % bucket
canonical_string += '/%s' % objectkey
params_found = False
for k, v in kwargs.items():
if k in special_params:
if params_found:
canonical_string += '&%s' % k
else:
canonical_string += '?%s' % k
params_found = True
print(canonical_string)
h = hmac.new(secret_key.encode(), canonical_string.encode(), digestmod=sha1)
signature = encodestring(h.digest()).strip()
url = 'https://%s.s3.amazonaws.com/%s' % (bucket, objectkey)
for key in headers.keys():
key_lower = key.lower()
if (
headers[key] and
key_lower not in interesting_headers
):
interesting_headers[key_lower] = headers[key].strip()
interesting_headers['Authorization'] = 'AWS %s:%s' % (
access_key, signature.decode())
return remove_blank({
'method': method,
'headers': interesting_headers,
'url': url,
})