2015-04-22 25 views
0

我有一個Python應用程序,使用博託,在那裏我給用戶一個臨時URL上傳文件到S3存儲桶。如何在使用boto的Key.generate_url方法將文件放在S3上時正確傳遞Content-MD5頭文件?

用戶的上傳訪問受限,我利用引導的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']) 
+0

你有沒有在請求開啓調試看到實際的HTTP請求中發送,包括頭文件?這可能很有趣。 – garnaat

+0

是的,當然有。它的發送正是我所要求的:'Content-Length'和'Content-MD5' - 我將其他頭部設置爲'None'的原因是刪除S3不期望的頭文件。 – pwalsh

回答

2

答案是,在Python 3中,在我的設置中,MD-5散列是一個字節字符串,其他所有內容都是文本字符串。解決方案是在將字符串添加到標題之前解碼字節字符串。

以前,我的校驗和(_file['md5'])作出這樣的:

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

現在,它是:

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