request.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. # Licensed to the Apache Software Foundation (ASF) under one
  2. # or more contributor license agreements. See the NOTICE file
  3. # distributed with this work for additional information
  4. # regarding copyright ownership. The ASF licenses this file
  5. # to you under the Apache License, Version 2.0 (the
  6. # "License"); you may not use this file except in compliance
  7. # with the License. You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. #
  12. #
  13. # Unless required by applicable law or agreed to in writing,
  14. # software distributed under the License is distributed on an
  15. # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. # KIND, either express or implied. See the License for the
  17. # specific language governing permissions and limitations
  18. # under the License.
  19. # coding=utf-8
  20. import abc
  21. from aliyunsdkcore.vendored.six import iterkeys
  22. from aliyunsdkcore.vendored.six import iteritems
  23. from aliyunsdkcore.vendored.six import add_metaclass
  24. from aliyunsdkcore.http import protocol_type
  25. from aliyunsdkcore.http import method_type as mt
  26. from aliyunsdkcore.http import format_type as ft
  27. from aliyunsdkcore.auth.composer import rpc_signature_composer as rpc_signer
  28. from aliyunsdkcore.auth.composer import roa_signature_composer as roa_signer
  29. from aliyunsdkcore.utils.parameter_helper import md5_sum
  30. from aliyunsdkcore.auth.algorithm import sha_hmac1
  31. from aliyunsdkcore.acs_exception import exceptions
  32. from aliyunsdkcore.acs_exception import error_code
  33. from aliyunsdkcore.compat import ensure_string
  34. from aliyunsdkcore.vendored.requests.structures import CaseInsensitiveDict
  35. """
  36. Acs request model.
  37. """
  38. STYLE_RPC = 'RPC'
  39. STYLE_ROA = 'ROA'
  40. _default_protocol_type = protocol_type.HTTP
  41. def set_default_protocol_type(user_protocol_type):
  42. global _default_protocol_type
  43. if user_protocol_type == protocol_type.HTTP or user_protocol_type == protocol_type.HTTPS:
  44. _default_protocol_type = user_protocol_type
  45. else:
  46. raise exceptions.ClientException(
  47. error_code.SDK_INVALID_PARAMS,
  48. "Invalid 'protocol_type', should be 'http' or 'https'"
  49. )
  50. def get_default_protocol_type():
  51. return _default_protocol_type
  52. @add_metaclass(abc.ABCMeta)
  53. class AcsRequest:
  54. """
  55. Acs request base class. This class wraps up common parameters for a request.
  56. """
  57. def __init__(self, product, version=None,
  58. action_name=None,
  59. location_service_code=None,
  60. location_endpoint_type='openAPI',
  61. accept_format=None,
  62. protocol_type=None,
  63. method=None):
  64. """
  65. :param product:
  66. :param version:
  67. :param action_name:
  68. :param params:
  69. :param resource_owner_account:
  70. :param protocol_type:
  71. :param accept_format:
  72. :return:
  73. """
  74. self._version = version
  75. self._product = product
  76. self._action_name = action_name
  77. self._protocol_type = protocol_type
  78. if self._protocol_type is None:
  79. self._protocol_type = _default_protocol_type
  80. self._accept_format = accept_format
  81. self._params = {}
  82. self._method = method
  83. self._header = {}
  84. if action_name is not None:
  85. self.add_header('x-acs-action', action_name)
  86. if version is not None:
  87. self.add_header('x-acs-version', version)
  88. self._body_params = {}
  89. self._uri_pattern = None
  90. self._uri_params = None
  91. self._content = None
  92. self._location_service_code = location_service_code
  93. self._location_endpoint_type = location_endpoint_type
  94. self.add_header('x-sdk-invoke-type', 'normal')
  95. self.endpoint = None
  96. self._extra_user_agent = {}
  97. self.string_to_sign = ''
  98. self._request_connect_timeout = None
  99. self._request_read_timeout = None
  100. self.request_network = "public"
  101. self.product_suffix = ""
  102. self.endpoint_map = None
  103. self.endpoint_regional = None
  104. def add_query_param(self, k, v):
  105. self._params[k] = v
  106. def add_body_params(self, k, v):
  107. self._body_params[k] = v
  108. def get_body_params(self):
  109. return self._body_params
  110. def get_uri_pattern(self):
  111. return self._uri_pattern
  112. def get_uri_params(self):
  113. return self._uri_params
  114. def get_product(self):
  115. return self._product
  116. def get_version(self):
  117. return self._version
  118. def get_action_name(self):
  119. return self._action_name
  120. def get_accept_format(self):
  121. return self._accept_format
  122. def get_protocol_type(self):
  123. return self._protocol_type
  124. def get_query_params(self):
  125. return self._params
  126. def get_method(self):
  127. return self._method
  128. def set_uri_pattern(self, pattern):
  129. self._uri_pattern = pattern
  130. def set_uri_params(self, params):
  131. self._uri_params = params
  132. def set_method(self, method):
  133. self._method = method
  134. def set_product(self, product):
  135. self._product = product
  136. def set_version(self, version):
  137. self._header['x-acs-version'] = version
  138. self._version = version
  139. def set_action_name(self, action_name):
  140. self._header['x-acs-action'] = action_name
  141. self._action_name = action_name
  142. def set_accept_format(self, accept_format):
  143. self._accept_format = accept_format
  144. def set_protocol_type(self, protocol_type):
  145. self._protocol_type = protocol_type
  146. def set_query_params(self, params):
  147. self._params = params
  148. def set_body_params(self, body_params):
  149. self._body_params = body_params
  150. def set_content(self, content):
  151. """
  152. :param content: ByteArray
  153. :return:
  154. """
  155. self._content = content
  156. def get_content(self):
  157. """
  158. :return: ByteArray
  159. """
  160. return self._content
  161. def get_headers(self):
  162. """
  163. :return: Dict
  164. """
  165. return self._header
  166. def set_headers(self, headers):
  167. """
  168. :param headers: Dict
  169. :return:
  170. """
  171. self._header = headers
  172. def add_header(self, k, v):
  173. self._header[k] = v
  174. def set_user_agent(self, agent):
  175. self.add_header('User-Agent', agent)
  176. def append_user_agent(self, key, value):
  177. self._extra_user_agent.update({key: value})
  178. def request_user_agent(self):
  179. request_user_agent = {}
  180. if 'User-Agent' in self.get_headers():
  181. request_user_agent.update({
  182. 'request': self.get_headers().get('User-Agent')
  183. })
  184. else:
  185. request_user_agent.update(self._extra_user_agent)
  186. return CaseInsensitiveDict(request_user_agent)
  187. def set_location_service_code(self, location_service_code):
  188. self._location_service_code = location_service_code
  189. def get_location_service_code(self):
  190. return self._location_service_code
  191. def get_location_endpoint_type(self):
  192. return self._location_endpoint_type
  193. def set_content_type(self, content_type):
  194. self.add_header("Content-Type", content_type)
  195. @abc.abstractmethod
  196. def get_style(self):
  197. pass
  198. @abc.abstractmethod
  199. def get_url(self, region_id, ak, secret):
  200. pass
  201. @abc.abstractmethod
  202. def get_signed_header(self, region_id, ak, secret):
  203. pass
  204. def set_endpoint(self, endpoint):
  205. self.endpoint = endpoint
  206. def get_connect_timeout(self):
  207. return self._request_connect_timeout
  208. def set_connect_timeout(self, connect_timeout):
  209. self._request_connect_timeout = connect_timeout
  210. def get_read_timeout(self):
  211. return self._request_read_timeout
  212. def set_read_timeout(self, read_timeout):
  213. self._request_read_timeout = read_timeout
  214. class RpcRequest(AcsRequest):
  215. """
  216. Class to compose an RPC style request with.
  217. """
  218. def __init__(
  219. self,
  220. product,
  221. version,
  222. action_name,
  223. location_service_code=None,
  224. location_endpoint_type='openAPI',
  225. format=None,
  226. protocol=None,
  227. signer=sha_hmac1):
  228. AcsRequest.__init__(
  229. self,
  230. product,
  231. version,
  232. action_name,
  233. location_service_code,
  234. location_endpoint_type,
  235. format,
  236. protocol,
  237. mt.GET)
  238. self._style = STYLE_RPC
  239. self._signer = signer
  240. def get_style(self):
  241. return self._style
  242. def _get_sign_params(self):
  243. req_params = self.get_query_params()
  244. if req_params is None:
  245. req_params = {}
  246. req_params['Version'] = self.get_version()
  247. req_params['Action'] = self.get_action_name()
  248. req_params['Format'] = self.get_accept_format()
  249. return req_params
  250. def get_url(self, region_id, access_key_id, access_key_secret):
  251. sign_params = dict(self._get_sign_params())
  252. if 'RegionId' not in iterkeys(sign_params):
  253. sign_params['RegionId'] = region_id
  254. url, string_to_sign = rpc_signer.get_signed_url(
  255. sign_params,
  256. access_key_id,
  257. access_key_secret,
  258. self.get_accept_format(),
  259. self.get_method(),
  260. self.get_body_params(),
  261. self._signer)
  262. self.string_to_sign = string_to_sign
  263. return url
  264. def get_signed_header(self, region_id=None, ak=None, secret=None):
  265. headers = {}
  266. for headerKey, headerValue in iteritems(self.get_headers()):
  267. if headerKey.startswith("x-acs-") or headerKey.startswith("x-sdk-"):
  268. headers[headerKey] = headerValue
  269. return headers
  270. class RoaRequest(AcsRequest):
  271. """
  272. Class to compose an ROA style request with.
  273. """
  274. def __init__(
  275. self,
  276. product,
  277. version,
  278. action_name,
  279. location_service_code=None,
  280. location_endpoint_type='openAPI',
  281. method=None,
  282. headers=None,
  283. uri_pattern=None,
  284. path_params=None,
  285. protocol=None):
  286. """
  287. :param product: String, mandatory
  288. :param version: String, mandatory
  289. :param action_name: String, mandatory
  290. :param method: String
  291. :param headers: Dict
  292. :param uri_pattern: String
  293. :param path_params: Dict
  294. :param protocol: String
  295. :return:
  296. """
  297. AcsRequest.__init__(
  298. self,
  299. product,
  300. version,
  301. action_name,
  302. location_service_code,
  303. location_endpoint_type,
  304. ft.RAW,
  305. protocol,
  306. method)
  307. self._style = STYLE_ROA
  308. self._method = method
  309. if headers is not None:
  310. self._header = headers
  311. self._uri_pattern = uri_pattern
  312. self._path_params = path_params
  313. def get_style(self):
  314. """
  315. :return: String
  316. """
  317. return self._style
  318. def get_path_params(self):
  319. return self._path_params
  320. def set_path_params(self, path_params):
  321. self._path_params = path_params
  322. def add_path_param(self, k, v):
  323. if self._path_params is None:
  324. self._path_params = {}
  325. self._path_params[k] = v
  326. def _get_sign_params(self):
  327. req_params = self.get_query_params()
  328. if req_params is None:
  329. req_params = {}
  330. self.add_header("x-acs-version", self.get_version())
  331. # req_params['Version'] = self.get_version()
  332. # req_params['Action'] = self.get_action_name()
  333. # req_params['Format'] = self.get_accept_format()
  334. return req_params
  335. def get_signed_header(self, region_id, ak, secret):
  336. """
  337. Generate signed header
  338. :param region_id: String
  339. :param ak: String
  340. :param secret: String
  341. :return: Dict
  342. """
  343. sign_params = dict(self._get_sign_params())
  344. if self.get_content() is not None:
  345. self.add_header(
  346. 'Content-MD5', md5_sum(self.get_content()))
  347. if 'RegionId' not in sign_params.keys():
  348. sign_params['RegionId'] = region_id
  349. self.add_header('x-acs-region-id', str(region_id))
  350. signed_headers, sign_to_string = roa_signer.get_signature_headers(
  351. sign_params,
  352. ak,
  353. secret,
  354. self.get_accept_format(),
  355. self.get_headers().copy(),
  356. self.get_uri_pattern(),
  357. self.get_path_params(),
  358. self.get_method())
  359. self.string_to_sign = sign_to_string
  360. return signed_headers
  361. def get_url(self, region_id, ak=None, secret=None):
  362. """
  363. Compose request url without domain
  364. :param region_id: String
  365. :return: String
  366. """
  367. sign_params = dict(self.get_query_params())
  368. if 'RegionId' not in sign_params.keys():
  369. sign_params['RegionId'] = region_id
  370. url = roa_signer.get_url(
  371. self.get_uri_pattern(),
  372. sign_params,
  373. self.get_path_params())
  374. return url
  375. class CommonRequest(AcsRequest):
  376. def __init__(self, domain=None, version=None, action_name=None, uri_pattern=None, product=None,
  377. location_endpoint_type='openAPI'):
  378. super(CommonRequest, self).__init__(product, version, action_name)
  379. self.request = None
  380. self.endpoint = domain
  381. self._version = version
  382. self._action_name = action_name
  383. self._uri_pattern = uri_pattern
  384. self._product = product
  385. self._location_endpoint_type = location_endpoint_type
  386. self._signer = sha_hmac1
  387. self.add_header('x-sdk-invoke-type', 'common')
  388. self._path_params = None
  389. self._method = "GET"
  390. def get_path_params(self):
  391. return self._path_params
  392. def set_path_params(self, path_params):
  393. self._path_params = path_params
  394. def add_path_param(self, k, v):
  395. if self._path_params is None:
  396. self._path_params = {}
  397. self._path_params[k] = v
  398. def set_domain(self, domain):
  399. self.endpoint = domain
  400. def get_domain(self):
  401. return self.endpoint
  402. def set_uri_pattern(self, uri_pattern):
  403. self._uri_pattern = uri_pattern
  404. def get_uri_pattern(self):
  405. return self._uri_pattern
  406. def set_product(self, product):
  407. self._product = product
  408. def get_product(self):
  409. return self._product
  410. def trans_to_acs_request(self):
  411. if not self._version:
  412. raise exceptions.ClientException(
  413. error_code.SDK_INVALID_PARAMS,
  414. 'common params [version] is required, cannot be empty')
  415. if not self._action_name and not self._uri_pattern:
  416. raise exceptions.ClientException(
  417. error_code.SDK_INVALID_PARAMS,
  418. 'At least one of [action] and [uri_pattern] has a value')
  419. if not self.endpoint and not self._product:
  420. raise exceptions.ClientException(
  421. error_code.SDK_INVALID_PARAMS,
  422. 'At least one of [domain] and [product_name] has a value')
  423. if self._uri_pattern:
  424. self._style = STYLE_ROA
  425. self.request = RoaRequest(product=self.get_product(), version=self.get_version(),
  426. action_name=self.get_action_name(),
  427. location_endpoint_type=self.get_location_endpoint_type()
  428. )
  429. self.fill_params()
  430. else:
  431. self._style = STYLE_RPC
  432. self.request = RpcRequest(product=self.get_product(), version=self.get_version(),
  433. action_name=self.get_action_name(),
  434. location_endpoint_type=self.get_location_endpoint_type(),
  435. )
  436. self.fill_params()
  437. def get_style(self):
  438. return self._style
  439. def get_url(self, region_id, ak, secret):
  440. return self.request.get_url(region_id, ak, secret)
  441. def get_signed_header(self, region_id, access_key_id, access_key_secret):
  442. return self.request.get_signed_header(region_id, access_key_id, access_key_secret)
  443. def fill_params(self):
  444. self.request.set_uri_pattern(self.get_uri_pattern())
  445. self.request.set_uri_params(self.get_uri_params())
  446. if self.get_style() == STYLE_ROA:
  447. self.request.set_path_params(self.get_path_params())
  448. self.request.set_method(self.get_method())
  449. self.request.set_product(self.get_product())
  450. self.request.set_version(self.get_version())
  451. self.request.set_action_name(self.get_action_name())
  452. self.request.set_accept_format(self.get_accept_format())
  453. self.request.set_protocol_type(self.get_protocol_type())
  454. self.request.set_query_params(self.get_query_params())
  455. self.request.set_content(self.get_content())
  456. self.request.set_headers(self.get_headers())
  457. self.request.set_location_service_code(
  458. self.get_location_service_code())
  459. self.request.set_body_params(self.get_body_params())