base.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. # -*- coding: utf-8 -*-
  2. '''
  3. Created on 2012-7-3
  4. @author: lijie.ma
  5. '''
  6. try: import httplib
  7. except ImportError:
  8. import http.client as httplib
  9. import sys
  10. import urllib
  11. import time
  12. import json
  13. import aliyun
  14. import itertools
  15. import mimetypes
  16. import base64
  17. import hmac
  18. import uuid
  19. from hashlib import sha1
  20. def sign(accessKeySecret, parameters):
  21. #===========================================================================
  22. # '''签名方法
  23. # @param secret: 签名需要的密钥
  24. # @param parameters: 支持字典和string两种
  25. # '''
  26. #===========================================================================
  27. # 如果parameters 是字典类的话
  28. sortedParameters = sorted(parameters.items(), key=lambda parameters: parameters[0])
  29. canonicalizedQueryString = ''
  30. for (k,v) in sortedParameters:
  31. canonicalizedQueryString += '&' + percent_encode(k) + '=' + percent_encode(v)
  32. stringToSign = 'POST&%2F&' + percent_encode(canonicalizedQueryString[1:])
  33. h = hmac.new(accessKeySecret + "&", stringToSign, sha1)
  34. signature = base64.encodestring(h.digest()).strip()
  35. return signature
  36. def percent_encode(encodeStr):
  37. encodeStr = str(encodeStr)
  38. res = urllib.quote(encodeStr.decode(sys.stdin.encoding).encode('utf8'), '')
  39. res = res.replace('+', '%20')
  40. res = res.replace('*', '%2A')
  41. res = res.replace('%7E', '~')
  42. return res
  43. def mixStr(pstr):
  44. if(isinstance(pstr, str)):
  45. return pstr
  46. elif(isinstance(pstr, unicode)):
  47. return pstr.encode('utf-8')
  48. else:
  49. return str(pstr)
  50. class FileItem(object):
  51. def __init__(self,filename=None,content=None):
  52. self.filename = filename
  53. self.content = content
  54. class MultiPartForm(object):
  55. """Accumulate the data to be used when posting a form."""
  56. def __init__(self):
  57. self.form_fields = []
  58. self.files = []
  59. self.boundary = "PYTHON_SDK_BOUNDARY"
  60. return
  61. def get_content_type(self):
  62. return 'multipart/form-data; boundary=%s' % self.boundary
  63. def add_field(self, name, value):
  64. """Add a simple field to the form data."""
  65. self.form_fields.append((name, str(value)))
  66. return
  67. def add_file(self, fieldname, filename, fileHandle, mimetype=None):
  68. """Add a file to be uploaded."""
  69. body = fileHandle.read()
  70. if mimetype is None:
  71. mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
  72. self.files.append((mixStr(fieldname), mixStr(filename), mixStr(mimetype), mixStr(body)))
  73. return
  74. def __str__(self):
  75. """Return a string representing the form data, including attached files."""
  76. # Build a list of lists, each containing "lines" of the
  77. # request. Each part is separated by a boundary string.
  78. # Once the list is built, return a string where each
  79. # line is separated by '\r\n'.
  80. parts = []
  81. part_boundary = '--' + self.boundary
  82. # Add the form fields
  83. parts.extend(
  84. [ part_boundary,
  85. 'Content-Disposition: form-data; name="%s"' % name,
  86. 'Content-Type: text/plain; charset=UTF-8',
  87. '',
  88. value,
  89. ]
  90. for name, value in self.form_fields
  91. )
  92. # Add the files to upload
  93. parts.extend(
  94. [ part_boundary,
  95. 'Content-Disposition: file; name="%s"; filename="%s"' % \
  96. (field_name, filename),
  97. 'Content-Type: %s' % content_type,
  98. 'Content-Transfer-Encoding: binary',
  99. '',
  100. body,
  101. ]
  102. for field_name, filename, content_type, body in self.files
  103. )
  104. # Flatten the list and add closing boundary marker,
  105. # then return CR+LF separated data
  106. flattened = list(itertools.chain(*parts))
  107. flattened.append('--' + self.boundary + '--')
  108. flattened.append('')
  109. return '\r\n'.join(flattened)
  110. class AliyunException(Exception):
  111. #===========================================================================
  112. # 业务异常类
  113. #===========================================================================
  114. def __init__(self):
  115. self.code = None
  116. self.message = None
  117. self.host = None
  118. self.requestId = None
  119. def __str__(self, *args, **kwargs):
  120. sb = "code=" + mixStr(self.code) +\
  121. " message=" + mixStr(self.message) +\
  122. " host=" + mixStr(self.host) +\
  123. " requestId=" + mixStr(self.requestId)
  124. return sb
  125. class RequestException(Exception):
  126. #===========================================================================
  127. # 请求连接异常类
  128. #===========================================================================
  129. pass
  130. class RestApi(object):
  131. #===========================================================================
  132. # Rest api的基类
  133. #===========================================================================
  134. def __init__(self, domain, port = 80):
  135. #=======================================================================
  136. # 初始化基类
  137. # Args @param domain: 请求的域名或者ip
  138. # @param port: 请求的端口
  139. #=======================================================================
  140. self.__domain = domain
  141. self.__port = port
  142. self.__httpmethod = "POST"
  143. if(aliyun.getDefaultAppInfo()):
  144. self.__access_key_id = aliyun.getDefaultAppInfo().accessKeyId
  145. self.__access_key_secret = aliyun.getDefaultAppInfo().accessKeySecret
  146. def get_request_header(self):
  147. return {
  148. 'Content-type': 'application/x-www-form-urlencoded',
  149. "Cache-Control": "no-cache",
  150. "Connection": "Keep-Alive",
  151. }
  152. def set_app_info(self, appinfo):
  153. #=======================================================================
  154. # 设置请求的app信息
  155. # @param appinfo: import aliyun
  156. # appinfo aliyun.appinfo(accessKeyId,accessKeySecret)
  157. #=======================================================================
  158. self.__access_key_id = appinfo.accessKeyId
  159. self.__access_key_secret = appinfo.accessKeySecret
  160. def getapiname(self):
  161. return ""
  162. def getMultipartParas(self):
  163. return [];
  164. def getTranslateParas(self):
  165. return {};
  166. def _check_requst(self):
  167. pass
  168. def getResponse(self, authrize=None, timeout=30):
  169. #=======================================================================
  170. # 获取response结果
  171. #=======================================================================
  172. connection = httplib.HTTPConnection(self.__domain, self.__port, timeout)
  173. timestamp = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
  174. apiname_split = self.getapiname().split(".")
  175. parameters = { \
  176. 'Format' : 'json', \
  177. 'Version' : apiname_split[4], \
  178. 'Action' : apiname_split[3], \
  179. 'AccessKeyId' : self.__access_key_id, \
  180. 'SignatureVersion' : '1.0', \
  181. 'SignatureMethod' : 'HMAC-SHA1', \
  182. 'SignatureNonce' : str(uuid.uuid1()), \
  183. 'TimeStamp' : timestamp, \
  184. 'partner_id' : '1.0',\
  185. }
  186. application_parameter = self.getApplicationParameters()
  187. for key in application_parameter.keys():
  188. parameters[key] = application_parameter[key]
  189. signature = sign(self.__access_key_secret,parameters)
  190. parameters['Signature'] = signature
  191. url = "/?" + urllib.urlencode(parameters)
  192. connection.connect()
  193. header = self.get_request_header();
  194. if(self.getMultipartParas()):
  195. form = MultiPartForm()
  196. for key in self.getMultipartParas():
  197. fileitem = getattr(self,key)
  198. if(fileitem and isinstance(fileitem,FileItem)):
  199. form.add_file(key,fileitem.filename,fileitem.content)
  200. body = str(form)
  201. header['Content-type'] = form.get_content_type()
  202. else:
  203. body = None
  204. connection.request(self.__httpmethod, url, body=body, headers=header)
  205. response = connection.getresponse();
  206. result = response.read()
  207. jsonobj = json.loads(result)
  208. return jsonobj
  209. def getApplicationParameters(self):
  210. application_parameter = {}
  211. for key, value in self.__dict__.iteritems():
  212. if not key.startswith("__") and not key in self.getMultipartParas() and not key.startswith("_RestApi__") and value is not None :
  213. if(key.startswith("_")):
  214. application_parameter[key[1:]] = value
  215. else:
  216. application_parameter[key] = value
  217. #查询翻译字典来规避一些关键字属性
  218. translate_parameter = self.getTranslateParas()
  219. for key, value in application_parameter.iteritems():
  220. if key in translate_parameter:
  221. application_parameter[translate_parameter[key]] = application_parameter[key]
  222. del application_parameter[key]
  223. return application_parameter