|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- # -*- coding: utf-8 -*-
-
- """
- oss2.exceptions
- ~~~~~~~~~~~~~~
-
- 异常类。
- """
-
- import re
- import base64
- import xml.etree.ElementTree as ElementTree
- from xml.parsers import expat
-
-
- from .compat import to_string
- from .headers import *
-
- _OSS_ERROR_TO_EXCEPTION = {} # populated at end of module
-
-
- OSS_CLIENT_ERROR_STATUS = -1
- OSS_REQUEST_ERROR_STATUS = -2
- OSS_INCONSISTENT_ERROR_STATUS = -3
- OSS_FORMAT_ERROR_STATUS = -4
- OSS_SELECT_CLIENT_ERROR_STATUS = -5
-
-
- class OssError(Exception):
- def __init__(self, status, headers, body, details):
- #: HTTP 状态码
- self.status = status
-
- #: 请求ID,用于跟踪一个OSS请求。提交工单时,最好能够提供请求ID
- self.request_id = headers.get(OSS_REQUEST_ID, '')
-
- #: HTTP响应体(部分)
- self.body = body
-
- #: 详细错误信息,是一个string到string的dict
- self.details = details
-
- #: OSS错误码
- self.code = self.details.get('Code', '')
-
- #: OSS错误信息
- self.message = self.details.get('Message', '')
-
- #: OSS新的错误码
- self.ec = self.details.get('EC', '')
-
- #: header信息
- self.headers = headers
-
- def __str__(self):
- error = {'status': self.status,
- OSS_REQUEST_ID : self.request_id,
- 'details': self.details}
- return str(error)
-
- def _str_with_body(self):
- error = {'status': self.status,
- OSS_REQUEST_ID : self.request_id,
- 'details': self.body}
- return str(error)
-
-
- class ClientError(OssError):
- def __init__(self, message):
- OssError.__init__(self, OSS_CLIENT_ERROR_STATUS, {}, 'ClientError: ' + message, {})
-
- def __str__(self):
- return self._str_with_body()
-
-
- class RequestError(OssError):
- def __init__(self, e):
- OssError.__init__(self, OSS_REQUEST_ERROR_STATUS, {}, 'RequestError: ' + str(e), {})
- self.exception = e
-
- def __str__(self):
- return self._str_with_body()
-
-
- class InconsistentError(OssError):
- def __init__(self, message, request_id=''):
- OssError.__init__(self, OSS_INCONSISTENT_ERROR_STATUS, {OSS_REQUEST_ID : request_id}, 'InconsistentError: ' + message, {})
-
- def __str__(self):
- return self._str_with_body()
-
-
- class OpenApiFormatError(OssError):
- def __init__(self, message):
- OssError.__init__(self, OSS_FORMAT_ERROR_STATUS, {}, message, {})
-
- def __str__(self):
- return self._str_with_body()
-
-
- class OpenApiServerError(OssError):
- def __init__(self, status, request_id, message, error_code):
- OssError.__init__(self, status, {OSS_REQUEST_ID : request_id}, '', {'Code': error_code, 'Message': message})
-
-
- class ServerError(OssError):
- pass
-
-
- class NotFound(ServerError):
- status = 404
- code = ''
-
-
- class MalformedXml(ServerError):
- status = 400
- code = 'MalformedXML'
-
-
- class InvalidRequest(ServerError):
- status = 400
- code = 'InvalidRequest'
-
-
- class OperationNotSupported(ServerError):
- status = 400
- code = 'OperationNotSupported'
-
-
- class RestoreAlreadyInProgress(ServerError):
- status = 409
- code = 'RestoreAlreadyInProgress'
-
-
- class InvalidArgument(ServerError):
- status = 400
- code = 'InvalidArgument'
-
- def __init__(self, status, headers, body, details):
- super(InvalidArgument, self).__init__(status, headers, body, details)
- self.name = details.get('ArgumentName')
- self.value = details.get('ArgumentValue')
-
-
- class InvalidDigest(ServerError):
- status = 400
- code = 'InvalidDigest'
-
-
- class InvalidObjectName(ServerError):
- status = 400
- code = 'InvalidObjectName'
-
-
- class NotImplemented(ServerError):
- status = 400
- code = 'NotImplemented'
-
-
- class InvalidEncryptionRequest(ServerError):
- status = 400
- code = 'InvalidEncryptionRequest'
-
- class BucketReplicationAlreadyExist(ServerError):
- status = 400
- code = 'BucketReplicationAlreadyExist'
-
- class NoSuchBucket(NotFound):
- status = 404
- code = 'NoSuchBucket'
-
-
- class NoSuchKey(NotFound):
- status = 404
- code = 'NoSuchKey'
-
-
- class NoSuchUpload(NotFound):
- status = 404
- code = 'NoSuchUpload'
-
-
- class NoSuchWebsite(NotFound):
- status = 404
- code = 'NoSuchWebsiteConfiguration'
-
-
- class NoSuchLifecycle(NotFound):
- status = 404
- code = 'NoSuchLifecycle'
-
-
- class NoSuchCors(NotFound):
- status = 404
- code = 'NoSuchCORSConfiguration'
-
-
- class NoSuchLiveChannel(NotFound):
- status = 404
- code = 'NoSuchLiveChannel'
-
-
- class NoSuchBucketPolicy(NotFound):
- status = 404
- code = 'NoSuchBucketPolicy'
-
- class NoSuchInventory(NotFound):
- status = 404
- code = 'NoSuchInventory'
-
- class NoSuchReplicationRule(NotFound):
- status = 404
- code = 'NoSuchReplicationRule'
-
- class Conflict(ServerError):
- status = 409
- code = ''
-
-
- class BucketNotEmpty(Conflict):
- status = 409
- code = 'BucketNotEmpty'
-
-
- class PositionNotEqualToLength(Conflict):
- status = 409
- code = 'PositionNotEqualToLength'
-
- def __init__(self, status, headers, body, details):
- super(PositionNotEqualToLength, self).__init__(status, headers, body, details)
- self.next_position = int(headers[OSS_NEXT_APPEND_POSITION])
-
-
- class ObjectNotAppendable(Conflict):
- status = 409
- code = 'ObjectNotAppendable'
-
-
- class ChannelStillLive(Conflict):
- status = 409
- code = 'ChannelStillLive'
-
-
- class LiveChannelDisabled(Conflict):
- status = 409
- code = 'LiveChannelDisabled'
-
-
- class PreconditionFailed(ServerError):
- status = 412
- code = 'PreconditionFailed'
-
-
- class NotModified(ServerError):
- status = 304
- code = ''
-
-
- class AccessDenied(ServerError):
- status = 403
- code = 'AccessDenied'
-
- class NoSuchServerSideEncryptionRule(NotFound):
- status = 404
- code = 'NoSuchServerSideEncryptionRule'
-
- class InvalidEncryptionAlgorithmError(ServerError):
- status = 400
- code = 'InvalidEncryptionAlgorithmError'
-
- class SelectOperationFailed(ServerError):
- code = 'SelectOperationFailed'
- def __init__(self, status, code, message):
- self.status = status
- self.code = code
- self.message = message
-
- def __str__(self):
- error = {'status': self.status,
- 'code': self.code,
- 'details': self.message}
- return str(error)
-
- class SelectOperationClientError(OssError):
- def __init__(self, message, request_id):
- OssError.__init__(self, OSS_SELECT_CLIENT_ERROR_STATUS, {'x-oss-request-id': request_id}, 'SelectOperationClientError: ' + message, {})
-
- def __str__(self):
- error = {'x-oss-request-id':self.request_id,
- 'message': self.message}
- return str(error)
-
- class SignatureDoesNotMatch(ServerError):
- status = 403
- code = 'SignatureDoesNotMatch'
-
- class ObjectAlreadyExists(ServerError):
- status = 400
- code = 'ObjectAlreadyExists'
-
- class PartNotSequential(ServerError):
- status = 400
- code = 'PartNotSequential'
-
- class NoSuchWORMConfiguration(ServerError):
- status = 404
- code = 'NoSuchWORMConfiguration'
-
- class WORMConfigurationLocked(ServerError):
- status = 403
- code = 'WORMConfigurationLocked'
-
- class InvalidWORMConfiguration(ServerError):
- status = 400
- code = 'InvalidWORMConfiguration'
-
- class NoSuchTransferAccelerationConfiguration(ServerError):
- status = 404
- code = 'NoSuchTransferAccelerationConfiguration'
-
- def make_exception(resp):
- status = resp.status
- headers = resp.headers
- body = resp.read(4096)
- if not body and headers.get('x-oss-err') is not None:
- try:
- value = base64.b64decode(to_string(headers.get('x-oss-err')))
- except:
- value = body
- details = _parse_error_body(value)
- else:
- details = _parse_error_body(body)
- code = details.get('Code', '')
-
- try:
- klass = _OSS_ERROR_TO_EXCEPTION[(status, code)]
- return klass(status, headers, body, details)
- except KeyError:
- return ServerError(status, headers, body, details)
-
-
- def _walk_subclasses(klass):
- for sub in klass.__subclasses__():
- yield sub
- for subsub in _walk_subclasses(sub):
- yield subsub
-
-
- for klass in _walk_subclasses(ServerError):
- status = getattr(klass, 'status', None)
- code = getattr(klass, 'code', None)
-
- if status is not None and code is not None:
- _OSS_ERROR_TO_EXCEPTION[(status, code)] = klass
-
-
- # XML parsing exceptions have changed in Python2.7 and ElementTree 1.3
- if hasattr(ElementTree, 'ParseError'):
- ElementTreeParseError = (ElementTree.ParseError, expat.ExpatError)
- else:
- ElementTreeParseError = (expat.ExpatError)
-
-
- def _parse_error_body(body):
- try:
- root = ElementTree.fromstring(body)
- if root.tag != 'Error':
- return {}
-
- details = {}
- for child in root:
- details[child.tag] = child.text
- return details
- except ElementTreeParseError:
- return _guess_error_details(body)
-
-
- def _guess_error_details(body):
- details = {}
- body = to_string(body)
-
- if '<Error>' not in body or '</Error>' not in body:
- return details
-
- m = re.search('<Code>(.*)</Code>', body)
- if m:
- details['Code'] = m.group(1)
-
- m = re.search('<Message>(.*)</Message>', body)
- if m:
- details['Message'] = m.group(1)
-
- return details
|