Skip to content

Commit d51aca6

Browse files
zhuxiaolong37huiguangjun
authored andcommitted
add EC (#329)
1 parent 539ca96 commit d51aca6

File tree

4 files changed

+116
-14
lines changed

4 files changed

+116
-14
lines changed

oss2/api.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ def get_object_meta(self, key, params=None, headers=None):
10561056
if Bucket.OBJECTMETA not in params:
10571057
params[Bucket.OBJECTMETA] = ''
10581058

1059-
resp = self.__do_object('GET', key, params=params, headers=headers)
1059+
resp = self.__do_object('HEAD', key, params=params, headers=headers)
10601060
logger.debug("Get object metadata done, req_id: {0}, status_code: {1}".format(resp.request_id, resp.status))
10611061
return GetObjectMetaResult(resp)
10621062

@@ -1074,12 +1074,17 @@ def object_exists(self, key, headers=None):
10741074
# 304 (NotModified);不存在,则会返回NoSuchKey。get_object会受回源的影响,如果配置会404回源,get_object会判断错误。
10751075
#
10761076
# 目前的实现是通过get_object_meta判断文件是否存在。
1077+
# get_object_meta 为200时,不会返回响应体,所以该接口把GET方法修改为HEAD 方式
1078+
# 同时, 对于head 请求,服务端会通过x-oss-err 返回 错误响应信息,
1079+
# 考虑到兼容之前的行为,增加exceptions.NotFound 异常 当作NoSuchKey
10771080

10781081
logger.debug("Start to check if object exists, bucket: {0}, key: {1}".format(self.bucket_name, to_string(key)))
10791082
try:
10801083
self.get_object_meta(key, headers=headers)
10811084
except exceptions.NoSuchKey:
10821085
return False
1086+
except exceptions.NotFound:
1087+
return False
10831088
except:
10841089
raise
10851090

oss2/exceptions.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@
88
"""
99

1010
import re
11-
11+
import base64
1212
import xml.etree.ElementTree as ElementTree
1313
from xml.parsers import expat
1414

1515

1616
from .compat import to_string
1717
from .headers import *
1818

19-
2019
_OSS_ERROR_TO_EXCEPTION = {} # populated at end of module
2120

2221

@@ -47,6 +46,12 @@ def __init__(self, status, headers, body, details):
4746
#: OSS错误信息
4847
self.message = self.details.get('Message', '')
4948

49+
#: OSS新的错误码
50+
self.ec = self.details.get('EC', '')
51+
52+
#: header信息
53+
self.headers = headers
54+
5055
def __str__(self):
5156
error = {'status': self.status,
5257
OSS_REQUEST_ID : self.request_id,
@@ -317,7 +322,14 @@ def make_exception(resp):
317322
status = resp.status
318323
headers = resp.headers
319324
body = resp.read(4096)
320-
details = _parse_error_body(body)
325+
if not body and headers.get('x-oss-err') is not None:
326+
try:
327+
value = base64.b64decode(to_string(headers.get('x-oss-err')))
328+
except:
329+
value = body
330+
details = _parse_error_body(value)
331+
else:
332+
details = _parse_error_body(body)
321333
code = details.get('Code', '')
322334

323335
try:

tests/test_exception_ec.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from .common import *
2+
3+
class TestExceptionEC(OssTestCase):
4+
def setUp(self):
5+
OssTestCase.setUp(self)
6+
7+
def tearDown(self):
8+
try:
9+
OssTestCase.tearDown(self)
10+
except:
11+
pass
12+
def test_1_exception_normal(self):
13+
key = 'a.txt'
14+
try:
15+
self.bucket.get_object(key)
16+
except oss2.exceptions.ServerError as e:
17+
self.assertEqual(e.headers.get('x-oss-ec'), '0026-00000001')
18+
self.assertEqual(e.ec, '0026-00000001')
19+
20+
def test_2_exception_head(self):
21+
key = 'a.txt'
22+
try:
23+
self.bucket.get_object_meta(key)
24+
except oss2.exceptions.OssError as e:
25+
self.assertEqual(e.ec, '0026-00000001')
26+
self.assertEqual(e.headers.get('x-oss-ec'), '0026-00000001')
27+
28+
def test_3_exception_head_err(self):
29+
# 模拟head请求下的签名错误
30+
auth = oss2.AuthV4(OSS_ID, OSS_SECRET)
31+
bucket = oss2.Bucket(auth, OSS_ENDPOINT, self.OSS_BUCKET, region='cn-hangzhou-test-1')
32+
key = 'a.txt'
33+
34+
try:
35+
bucket.head_object(key)
36+
except oss2.exceptions.OssError as e:
37+
self.assertEqual(e.ec, '0002-00000061')
38+
self.assertEqual(e.headers.get('x-oss-ec'), '0002-00000061')
39+
self.assertEqual(e.code, 'InvalidArgument')
40+
self.assertEqual(e.message, 'Authorization header is invalid.')
41+
42+
if __name__ == '__main__':
43+
unittest.main()

unittests/test_object.py

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def test_head(self, do_request):
129129

130130
@patch('oss2.Session.do_request')
131131
def test_object_exists_true(self, do_request):
132-
request_text = '''GET /sbowspxjhmccpmesjqcwagfw?objectMeta HTTP/1.1
132+
request_text = '''HEAD /sbowspxjhmccpmesjqcwagfw?objectMeta HTTP/1.1
133133
Host: ming-oss-share.oss-cn-hangzhou.aliyuncs.com
134134
Accept-Encoding: identity
135135
Connection: keep-alive
@@ -154,7 +154,7 @@ def test_object_exists_true(self, do_request):
154154

155155
@patch('oss2.Session.do_request')
156156
def test_object_exists_false(self, do_request):
157-
request_text = '''GET /sbowspxjhmccpmesjqcwagfw?objectMeta HTTP/1.1
157+
request_text = '''HEAD /sbowspxjhmccpmesjqcwagfw?objectMeta HTTP/1.1
158158
Host: ming-oss-share.oss-cn-hangzhou.aliyuncs.com
159159
Accept-Encoding: identity
160160
Connection: keep-alive
@@ -170,15 +170,57 @@ def test_object_exists_false(self, do_request):
170170
Content-Length: 287
171171
Connection: keep-alive
172172
x-oss-request-id: 566B6C3D6086505A0CFF0F68
173+
'''
173174

174-
<?xml version="1.0" encoding="UTF-8"?>
175-
<Error>
176-
<Code>NoSuchKey</Code>
177-
<Message>The specified key does not exist.</Message>
178-
<RequestId>566B6C3D6086505A0CFF0F68</RequestId>
179-
<HostId>ming-oss-share.oss-cn-hangzhou.aliyuncs.com</HostId>
180-
<Key>sbowspxjhmccpmesjqcwagfw</Key>
181-
</Error>'''
175+
req_info = mock_response(do_request, response_text)
176+
self.assertTrue(not bucket().object_exists('sbowspxjhmccpmesjqcwagfw'))
177+
self.assertRequest(req_info, request_text)
178+
179+
@patch('oss2.Session.do_request')
180+
def test_object_exists_false_with_err_header(self, do_request):
181+
request_text = '''HEAD /sbowspxjhmccpmesjqcwagfw?objectMeta HTTP/1.1
182+
Host: ming-oss-share.oss-cn-hangzhou.aliyuncs.com
183+
Accept-Encoding: identity
184+
Connection: keep-alive
185+
date: Sat, 12 Dec 2015 00:37:17 GMT
186+
User-Agent: aliyun-sdk-python/2.0.2(Windows/7/;3.3.3)
187+
Accept: */*
188+
authorization: OSS ZCDmm7TPZKHtx77j:wopWcmMd/70eNKYOc9M6ZA21yY8='''
189+
190+
response_text = '''HTTP/1.1 404 Not Found
191+
Server: AliyunOSS
192+
Date: Sat, 12 Dec 2015 00:37:17 GMT
193+
Content-Type: application/xml
194+
Content-Length: 287
195+
Connection: keep-alive
196+
x-oss-request-id: 566B6C3D6086505A0CFF0F68
197+
x-oss-err: PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxFcnJvcj4NCiAgPENvZGU+Tm9TdWNoS2V5PC9Db2RlPg0KICA8TWVzc2FnZT5UaGUgc3BlY2lmaWVkIGtleSBkb2VzIG5vdCBleGlzdC48L01lc3NhZ2U+DQogIDxSZXF1ZXN0SWQ+NTY2QjZDM0Q2MDg2NTA1QTBDRkYwRjY4PC9SZXF1ZXN0SWQ+DQogIDxIb3N0SWQ+bWluZy1vc3Mtc2hhcmUub3NzLWNuLWhhbmd6aG91LmFsaXl1bmNzLmNvbTwvSG9zdElkPg0KICA8S2V5PnNib3dzcHhqaG1jY3BtZXNqcWN3YWdmdzwvS2V5Pg0KPC9FcnJvcj4=
198+
'''
199+
200+
req_info = mock_response(do_request, response_text)
201+
self.assertTrue(not bucket().object_exists('sbowspxjhmccpmesjqcwagfw'))
202+
self.assertRequest(req_info, request_text)
203+
204+
@patch('oss2.Session.do_request')
205+
def test_object_exists_false_with_invalid_err_header(self, do_request):
206+
request_text = '''HEAD /sbowspxjhmccpmesjqcwagfw?objectMeta HTTP/1.1
207+
Host: ming-oss-share.oss-cn-hangzhou.aliyuncs.com
208+
Accept-Encoding: identity
209+
Connection: keep-alive
210+
date: Sat, 12 Dec 2015 00:37:17 GMT
211+
User-Agent: aliyun-sdk-python/2.0.2(Windows/7/;3.3.3)
212+
Accept: */*
213+
authorization: OSS ZCDmm7TPZKHtx77j:wopWcmMd/70eNKYOc9M6ZA21yY8='''
214+
215+
response_text = '''HTTP/1.1 404 Not Found
216+
Server: AliyunOSS
217+
Date: Sat, 12 Dec 2015 00:37:17 GMT
218+
Content-Type: application/xml
219+
Content-Length: 287
220+
Connection: keep-alive
221+
x-oss-request-id: 566B6C3D6086505A0CFF0F68
222+
x-oss-err: PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxFcnJvcj4NCiAgPENvZGU+Tm9TdWNoS2V5PC9Db2RlPg0KICA8TWVzc2FnZT5UaGUgc3BlY2lmaWVkIGtleSBkb2VzIG5vdCBleGlzdC48L01lc3NhZ2U+DQogIDxSZXF1ZXN0SWQ+NTY2QjZDM0Q2MDg2NTA1QTBDRkYwRjY4PC9SZXF1ZXN0SWQ+DQogIDxIb3N0SWQ+bWluZy1vc3Mtc2hhcmUub3NzLWNuLWhhbmd6aG91LmFsaXl1bmNzLmNvbTwvSG9zdElkPg0KICA8S2V5PnNib3dzcHhqaG1jY3BtZXNqcWN3YWdmdzwvS2V5Pg0KPC9FcnJvcj4
223+
'''
182224

183225
req_info = mock_response(do_request, response_text)
184226
self.assertTrue(not bucket().object_exists('sbowspxjhmccpmesjqcwagfw'))

0 commit comments

Comments
 (0)