如何使用boto的Key.generate_url方法在S3上放置文件时正确传递Content-MD5标头?

时间:2015-04-22 11:26:32

标签: python amazon-s3 python-requests boto

我有一个Python应用程序,使用boto,我给用户一个临时URL,将文件上传到S3存储桶。

用户的上传访问权限有限,我使用了boot的Key.generate_url方法来创建接受PUT请求的临时URL。

我的工作正常,但我想确保在生成密钥和实际上传时间之间不会修改用户有效负载。

因此,我尝试使用S3的Content-MD5支持来确保校验和匹配。

但是,当我向代码添加Content-MD5标头时,PUT请求失败。

在下面的代码示例中,如果我删除每个步骤(geturl和uploadfile)的Content-MD5标头,那么一切都按预期工作。

注意我已经验证我的校验和是正确的:如果我上传的文件没有Content-MD5标题,那么我会在S3上访问MD5,它确实与我的本地哈希匹配。

以下是我获得密钥的方式:

# geturl
# s3key is a Key instance
# _file is a dict with some info on a file to be uploaded
s3headers = {
    'Content-Length': _file['length'],
    'Content-MD5': _file['md5']
}
s3url = s3key.generate_url(self.ACCESS_KEY_EXPIRES_IN, 'PUT',
                           headers=s3headers, force_http=True)
_parsed = compat.parse.urlparse(s3url)
_file['upload_url'] = '{0}://{1}{2}'.format(_parsed.scheme, _parsed.netloc, _parsed.path)
_file['upload_params'] = compat.parse.parse_qs(_parsed.query)

以下是我上传文件的方式:

# uploadfile
headers = {'Content-Length': _file['length'],
       'Content-MD5': _file['md5'],
       'Content-Type': None,
       'Connection': None,
       'User-Agent': None,
       'Accept-Encoding': None,
       'Accept': None
}
stream = io.open(_file['local'])
response = requests.put(_file['upload_url'], data=stream, headers=headers, params=_file['upload_params'])

1 个答案:

答案 0 :(得分:2)

答案是在Python 3上,在我的设置中,MD-5哈希是一个字节字符串,其他一切都是文本字符串。解决方案是在将字节串添加到标题之前对其进行解码。

以前,我的校验和(_file['md5'])是这样的:

checksum = base64.b64encode(hasher.digest())

现在,它是:

checksum = base64.b64encode(hasher.digest()).decode('utf-8')