diff --git a/aliyun/log/auth.py b/aliyun/log/auth.py index 9514977..a8d33fd 100644 --- a/aliyun/log/auth.py +++ b/aliyun/log/auth.py @@ -68,13 +68,17 @@ def sign_request(self, method, resource, params, headers, body, compute_content_ headers['x-log-signaturemethod'] = 'hmac-sha1' headers['Date'] = self._getGMT() + content_md5 = None + # we don't need content-md5 in signature if compute_content_hash is False if body and compute_content_hash: - headers['Content-MD5'] = Util.cal_md5(body) + content_md5 = Util.cal_md5(body) + headers['Content-MD5'] = content_md5 + if not credentials.get_access_key_secret(): return six.b('') content = method + '\n' - if 'Content-MD5' in headers: - content += headers['Content-MD5'] + if content_md5 is not None: + content += content_md5 content += '\n' if 'Content-Type' in headers: content += headers['Content-Type'] @@ -87,6 +91,8 @@ def sign_request(self, method, resource, params, headers, body, compute_content_ headers['x-log-date'] = headers['Date'] # bypass some proxy doesn't allow "Date" in header issue. +_EMPTY_CONTENT_SHA256 = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' + class AuthV4(AuthBase): def __init__(self, credentials_provider, region): AuthBase.__init__(self, credentials_provider) @@ -94,16 +100,18 @@ def __init__(self, credentials_provider, region): def sign_request(self, method, resource, params, headers, body, compute_content_hash=True): current_time = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ") - headers['Authorization'] = self._do_sign_request(method, resource, params, headers, body, current_time) + headers['Authorization'] = self._do_sign_request(method, resource, params, headers, body, current_time, compute_content_hash=compute_content_hash) - def _do_sign_request(self, method, resource, params, headers, body, current_time): + def _do_sign_request(self, method, resource, params, headers, body, current_time, compute_content_hash=True): credentials = self.credentials_provider.get_credentials() if credentials.get_security_token(): headers['x-acs-security-token'] = credentials.get_security_token() - content_sha256 = sha256(body).hexdigest() \ - if body else 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' + content_sha256 = _EMPTY_CONTENT_SHA256 + if compute_content_hash and body: + content_sha256 = sha256(body).hexdigest() + headers['x-log-content-sha256'] = content_sha256 headers['x-log-date'] = current_time current_date = current_time[:8] @@ -111,7 +119,11 @@ def _do_sign_request(self, method, resource, params, headers, body, current_time signed_headers = '' for original_key, value in headers.items(): key = original_key.lower() - if key == 'content-type' or key == 'host' or key.startswith('x-log-') or key.startswith('x-acs-'): + if ( + key == "content-type" + or key == "host" + or Util._is_extra_sign_header(key) + ): canonical_headers[key] = value headers_to_string = '' for key, value in sorted(canonical_headers.items()): diff --git a/aliyun/log/object_response.py b/aliyun/log/object_response.py index 731385d..e4a9bb7 100644 --- a/aliyun/log/object_response.py +++ b/aliyun/log/object_response.py @@ -55,13 +55,6 @@ def get_etag(self): """ return Util.h_v_td(self.headers, 'ETag', None) - def get_last_modified(self): - """ Get the last modified time of the object. - - :return: string, last modified time, may be None if not set - """ - return Util.h_v_td(self.headers, 'Last-Modified', None) - def get_content_type(self): """ Get the content type of the object. diff --git a/aliyun/log/util.py b/aliyun/log/util.py index 194d764..afcc3dc 100755 --- a/aliyun/log/util.py +++ b/aliyun/log/util.py @@ -40,6 +40,7 @@ def base64_decodestring(s): s = s.encode('utf8') return base64.decodebytes(s).decode('utf8') +_EXCLUDE_SIGN_HEADER_PREFIX = 'x-log-meta-' class Util(object): @staticmethod @@ -90,10 +91,18 @@ def hmac_sha1(content, key): def canonicalized_log_headers(headers): content = '' for key in sorted(six.iterkeys(headers)): - if key[:6].lower() in ('x-log-', 'x-acs-'): # x-log- header + if Util._is_extra_sign_header(key): content += key + ':' + str(headers[key]) + "\n" return content + @staticmethod + def _is_extra_sign_header(key): + lower_key = key.lower() + return lower_key.startswith("x-acs-") or ( + lower_key.startswith("x-log-") + and not lower_key.startswith(_EXCLUDE_SIGN_HEADER_PREFIX) + ) + @staticmethod def url_encode(params): for key, value in params.items(): # urllib.urlencode accept 8-bit str diff --git a/aliyun/log/version.py b/aliyun/log/version.py index a22c346..3cb5462 100644 --- a/aliyun/log/version.py +++ b/aliyun/log/version.py @@ -1,4 +1,4 @@ -__version__ = '0.9.38' +__version__ = '0.9.39' import sys OS_VERSION = str(sys.platform) diff --git a/doc/tutorials/object_api.md b/doc/tutorials/object_api.md index 809b83a..4423c34 100644 --- a/doc/tutorials/object_api.md +++ b/doc/tutorials/object_api.md @@ -139,7 +139,6 @@ response = client.get_object(project, logstore, object_name) # 访问响应数据 print('ETag:', response.get_etag()) -print('Last Modified:', response.get_last_modified()) print('Content Type:', response.get_content_type()) print('Content Length:', len(response.get_body())) print('Content:', response.get_body()) diff --git a/tests/sample_object_api.py b/tests/sample_object_api.py index d2b6b1c..6e1fe79 100644 --- a/tests/sample_object_api.py +++ b/tests/sample_object_api.py @@ -39,7 +39,6 @@ def sample_put_object(): response.log_print() print(response.get_body()) print('etag', response.get_etag()) - print('last_modified', response.get_last_modified()) print('content-type', response.get_content_type()) except LogException as e: @@ -67,7 +66,6 @@ def sample_put_with_header(): response.log_print() print(response.get_body()) print('etag', response.get_etag()) - print('last_modified', response.get_last_modified()) print('content-type', response.get_content_type()) except LogException as e: print("Put object failed:", e) @@ -101,7 +99,6 @@ def sample_put_with_md5(): response.log_print() print(response.get_body()) print('etag', response.get_etag()) - print('last_modified', response.get_last_modified()) print('content-type', response.get_content_type()) except LogException as e: print("Put object failed:", e)