Skip to content

Commit 14032dc

Browse files
update 3.25.8
1 parent 0d76b48 commit 14032dc

15 files changed

+1021
-125
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
Version 3.25.8
2+
3+
New features:
4+
5+
When new ObsClient with ECS agency, the more secure IMDSv2 interface will be prioritized for interacting with ECS services.
6+
7+
Fix problem:
8+
9+
1. Fix the issue where the ObsClient.downloadFile interface cannot retry after enabling crc64, if the verification fails.
10+
-------------------------------------------------------------------------------------------------
111
Version 3.25.3
212

313
New Features:

README_CN.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
Version 3.25.3
1+
Version 3.25.8
2+
3+
新特性:
4+
5+
1. 使用ECS委托初始化ObsClient时会优先使用更安全的IMDSv2接口与ECS服务交互。
6+
7+
修复问题:
8+
9+
1. 修复ObsClient.downloadFile接口开启crc64和断点续传后,如果校验失败,无法重试的问题。
10+
-------------------------------------------------------------------------------------------------
11+
Version 3.25.3
212

313
新特性:
414

src/obs/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from obs.model import Options, PutObjectHeader, AppendObjectHeader, AppendObjectContent, RedirectAllRequestTo
2424
from obs.model import Redirect, RoutingRule, Tag, TagInfo, Transition, NoncurrentVersionTransition, Rule, Versions, AbortIncompleteMultipartUpload
2525
from obs.model import Object, WebsiteConfiguration, Logging, CompleteMultipartUploadRequest, DeleteObjectsRequest,CustomDomainConfiguration
26-
from obs.model import ListMultipartUploadsRequest, GetObjectRequest, UploadFileHeader, Payer
26+
from obs.model import ListMultipartUploadsRequest, GetObjectRequest, UploadFileHeader, Payer, ClientVerify
2727
from obs.model import ExtensionHeader, FetchStatus, BucketAliasModel, ListBucketAliasModel
2828
from obs.workflow import WorkflowClient
2929
from obs.crypto_client import CryptoObsClient
@@ -97,5 +97,6 @@
9797
'CtrRSACipherGenerator',
9898
'BucketAliasModel',
9999
'ListBucketAliasModel',
100-
'CustomDomainConfiguration'
100+
'CustomDomainConfiguration',
101+
'ClientVerify'
101102
]

src/obs/client.py

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,9 @@ def __getattr__(self, item):
199199

200200
class _BasicClient(object):
201201
def __init__(self, access_key_id='', secret_access_key='', is_secure=True, server=None,
202-
signature='obs', region='region', path_style=False, ssl_verify=False,
202+
signature='obs', region='region', path_style=False, ssl_verify=False, is_use_gmssl=False,
203203
port=None, max_retry_count=3, timeout=60, chunk_size=const.READ_ONCE_LENGTH,
204-
long_conn_mode=False, proxy_host=None, proxy_port=None,
204+
long_conn_mode=False, proxy_host=None, proxy_port=None, client_verify=None,
205205
proxy_username=None, proxy_password=None, security_token=None,
206206
custom_ciphers=None, use_http2=False, is_signature_negotiation=True, is_cname=False,
207207
max_redirect_count=10, security_providers=None, security_provider_policy=None, client_mode='obs',
@@ -239,7 +239,8 @@ def __init__(self, access_key_id='', secret_access_key='', is_secure=True, serve
239239
self.is_signature_negotiation = is_signature_negotiation
240240
self.is_cname = is_cname
241241
self.max_redirect_count = max_redirect_count
242-
242+
self.is_use_gmssl = is_use_gmssl
243+
self.client_verify = client_verify
243244
if client_mode == 'obs':
244245
if self.path_style or self.is_cname:
245246
self.is_signature_negotiation = False
@@ -364,30 +365,45 @@ def _init_connHolder(self):
364365
self.connHolder = {'connSet': Queue(), 'lock': threading.Lock()}
365366

366367
def _init_ssl_context(self, custom_ciphers):
367-
try:
368-
import ssl
369-
if hasattr(ssl, 'SSLContext'):
368+
import ssl
369+
if hasattr(ssl, 'SSLContext'):
370+
if self.is_use_gmssl:
371+
if not hasattr(ssl, 'PROTOCOL_GMTLS'):
372+
raise Exception('ssl not support PROTOCOL_GMTLS.')
373+
context = ssl.SSLContext(ssl.PROTOCOL_GMTLS)
374+
context.set_ciphers('ECC-SM4-SM3:ECDHE-SM4-SM3')
375+
else:
370376
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
371-
context.options |= ssl.OP_NO_SSLv2
372-
context.options |= ssl.OP_NO_SSLv3
373-
if custom_ciphers is not None:
374-
custom_ciphers = util.to_string(custom_ciphers).strip()
375-
if custom_ciphers != '' and hasattr(context, 'set_ciphers') and callable(context.set_ciphers):
376-
context.set_ciphers(custom_ciphers)
377-
if self.ssl_verify:
378-
import _ssl
379-
cafile = util.to_string(self.ssl_verify)
380-
context.options |= getattr(_ssl, "OP_NO_COMPRESSION", 0)
381-
context.verify_mode = ssl.CERT_REQUIRED
382-
if os.path.isfile(cafile):
383-
context.load_verify_locations(cafile)
384-
else:
385-
context.verify_mode = ssl.CERT_NONE
386-
if hasattr(context, 'check_hostname'):
387-
context.check_hostname = False
388-
self.context = context
389-
except Exception:
390-
print(traceback.format_exc())
377+
context.options |= ssl.OP_NO_SSLv2
378+
context.options |= ssl.OP_NO_SSLv3
379+
if custom_ciphers is not None:
380+
custom_ciphers = util.to_string(custom_ciphers).strip()
381+
if custom_ciphers != '' and hasattr(context, 'set_ciphers') and callable(context.set_ciphers):
382+
context.set_ciphers(custom_ciphers)
383+
if self.ssl_verify:
384+
import _ssl
385+
cafile = util.to_string(self.ssl_verify)
386+
context.options |= getattr(_ssl, "OP_NO_COMPRESSION", 0)
387+
context.verify_mode = ssl.CERT_REQUIRED
388+
if os.path.isfile(cafile):
389+
context.load_verify_locations(cafile)
390+
else:
391+
context.verify_mode = ssl.CERT_NONE
392+
is_client_sign_verify = self.client_verify and self.client_verify.clientCert and \
393+
self.client_verify.clientKey
394+
is_client_enc_verify = self.client_verify and self.client_verify.clientEncCert and \
395+
self.client_verify.clientEncKey
396+
if is_client_sign_verify:
397+
context.load_cert_chain(certfile=util.to_string(self.client_verify.clientCert),
398+
keyfile=util.to_string(self.client_verify.clientKey),
399+
password=util.to_string(self.client_verify.clientKeyPassword))
400+
if is_client_enc_verify:
401+
context.load_cert_chain(certfile=util.to_string(self.client_verify.clientEncCert),
402+
keyfile=util.to_string(self.client_verify.clientEncKey),
403+
password=util.to_string(self.client_verify.clientEncKeyPassword))
404+
if hasattr(context, 'check_hostname'):
405+
context.check_hostname = False
406+
self.context = context
391407

392408
def close(self):
393409
if self.connHolder is not None:
@@ -502,7 +518,7 @@ def _make_request_with_retry(self, methodType, bucketName, objectKey=None, pathA
502518
if flag >= self.max_retry_count or readable:
503519
return self._make_error_result(e, ret)
504520
flag += 1
505-
time.sleep(math.pow(2, flag) * 0.05)
521+
time.sleep(math.pow(2, flag) * 0.1)
506522
self.log_client.log(WARNING, 'request again, time:%d' % int(flag))
507523
continue
508524

@@ -824,7 +840,9 @@ def _parse_content(self, objectKey, conn, response, download_start='',
824840
result_wrapper = ResponseWrapper(conn, response, self.connHolder, content_length, notifier, obs_crc64=obs_crc64)
825841
self.log_client.log(DEBUG, 'CRC64 from the server is {0}'.format(obs_crc64))
826842
else:
827-
raise Exception('No CRC64 is obtained from the server.')
843+
result_wrapper = ResponseWrapper(conn, response, self.connHolder, content_length, notifier)
844+
self.log_client.log(WARNING, 'object {0} not get CRC64 from the server.'.format(objectKey))
845+
828846
else:
829847
result_wrapper = ResponseWrapper(conn, response, self.connHolder, content_length, notifier)
830848
if loadStreamInMemory:
@@ -1248,9 +1266,7 @@ def _createPostSignature(self, bucketName=None, objectKey=None, expires=300, for
12481266
if matchAnyKey:
12491267
policy.append('["starts-with", "$key", ""],')
12501268

1251-
policy.append(']}')
1252-
1253-
originPolicy = ''.join(policy)
1269+
originPolicy = ''.join(policy).rstrip(',') + ']}'
12541270

12551271
policy = util.base64_encode(originPolicy)
12561272

src/obs/const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101
DEFAULT_TASK_QUEUE_SIZE = 20000
102102
CONNECTION_POOL_SIZE = 10
103103

104-
OBS_SDK_VERSION = '3.25.3'
104+
OBS_SDK_VERSION = '3.25.8'
105105

106106
V2_META_HEADER_PREFIX = 'x-amz-meta-'
107107
V2_HEADER_PREFIX = 'x-amz-'

src/obs/convertor.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,14 @@ def trans_custom_domain_cert(self, certificate, domainName):
641641
if certificate.get("certificateChain", None):
642642
ET.SubElement(root, "CertificateChain").text = util.to_string(certificate.get("certificateChain", None))
643643
ET.SubElement(root, "PrivateKey").text = util.to_string(certificate.get("privateKey"))
644+
if certificate.get("certificateType", None):
645+
ET.SubElement(root, "CertificateType").text = util.to_string(certificate.get("certificateType", None))
646+
if certificate.get("encCertificate", None):
647+
ET.SubElement(root, "ENCCertificate").text = util.to_string(certificate.get("encCertificate", None))
648+
if certificate.get("encPrivateKey", None):
649+
ET.SubElement(root, "ENCPrivateKey").text = util.to_string(certificate.get("encPrivateKey", None))
650+
if util.to_string(certificate.get("deleteCertificate", None)):
651+
ET.SubElement(root, "DeleteCertificate").text = util.to_string(certificate.get("deleteCertificate", None))
644652
entity = ET.tostring(root, "UTF-8")
645653
if len(entity) > const.MAX_CERT_XML_BODY_SIZE:
646654
error_message = "XML body size exceeds {} KB limit".format(const.MAX_CERT_XML_BODY_SIZE / 1024)
@@ -1336,7 +1344,12 @@ def parseGetBucketCustomDomain(self, xml, headers=None):
13361344
d = self._find_item(domain, "CreateTime")
13371345
certificate_id = self._find_item(domain, "CertificateId")
13381346
create_time = DateTime.UTCToLocal(d)
1339-
curr_bucket = BucketCustomDomain(domain_name=domain_name,create_time=create_time,certificate_id=certificate_id)
1347+
name = self._find_item(domain, "Name")
1348+
certificate_type = self._find_item(domain, "CertificateType")
1349+
e = self._find_item(domain, "ExpiredTime")
1350+
expired_time = DateTime.UTCToLocal(e)
1351+
curr_bucket = BucketCustomDomain(domainName=domain_name, createTime=create_time, certificateId=certificate_id,
1352+
name=name, certificateType=certificate_type, expiredTime=expired_time)
13401353
entries.append(curr_bucket)
13411354

13421355
return ListBucketCustomDomainsResponse(domains=entries)

0 commit comments

Comments
 (0)