request.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  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. self._body_params = {}
  85. self._uri_pattern = None
  86. self._uri_params = None
  87. self._content = None
  88. self._location_service_code = location_service_code
  89. self._location_endpoint_type = location_endpoint_type
  90. self.add_header('x-sdk-invoke-type', 'normal')
  91. self.endpoint = None
  92. self._extra_user_agent = {}
  93. self.string_to_sign = ''
  94. self._request_connect_timeout = None
  95. self._request_read_timeout = None
  96. self.request_network = "public"
  97. self.product_suffix = ""
  98. self.endpoint_map = None
  99. self.endpoint_regional = None
  100. def add_query_param(self, k, v):
  101. self._params[k] = v
  102. def add_body_params(self, k, v):
  103. self._body_params[k] = v
  104. def get_body_params(self):
  105. return self._body_params
  106. def get_uri_pattern(self):
  107. return self._uri_pattern
  108. def get_uri_params(self):
  109. return self._uri_params
  110. def get_product(self):
  111. return self._product
  112. def get_version(self):
  113. return self._version
  114. def get_action_name(self):
  115. return self._action_name
  116. def get_accept_format(self):
  117. return self._accept_format
  118. def get_protocol_type(self):
  119. return self._protocol_type
  120. def get_query_params(self):
  121. return self._params
  122. def get_method(self):
  123. return self._method
  124. def set_uri_pattern(self, pattern):
  125. self._uri_pattern = pattern
  126. def set_uri_params(self, params):
  127. self._uri_params = params
  128. def set_method(self, method):
  129. self._method = method
  130. def set_product(self, product):
  131. self._product = product
  132. def set_version(self, version):
  133. self._version = version
  134. def set_action_name(self, action_name):
  135. self._action_name = action_name
  136. def set_accept_format(self, accept_format):
  137. self._accept_format = accept_format
  138. def set_protocol_type(self, protocol_type):
  139. self._protocol_type = protocol_type
  140. def set_query_params(self, params):
  141. self._params = params
  142. def set_body_params(self, body_params):
  143. self._body_params = body_params
  144. def set_content(self, content):
  145. """
  146. :param content: ByteArray
  147. :return:
  148. """
  149. self._content = content
  150. def get_content(self):
  151. """
  152. :return: ByteArray
  153. """
  154. return self._content
  155. def get_headers(self):
  156. """
  157. :return: Dict
  158. """
  159. return self._header
  160. def set_headers(self, headers):
  161. """
  162. :param headers: Dict
  163. :return:
  164. """
  165. self._header = headers
  166. def add_header(self, k, v):
  167. self._header[k] = v
  168. def set_user_agent(self, agent):
  169. self.add_header('User-Agent', agent)
  170. def append_user_agent(self, key, value):
  171. self._extra_user_agent.update({key: value})
  172. def request_user_agent(self):
  173. request_user_agent = {}
  174. if 'User-Agent' in self.get_headers():
  175. request_user_agent.update({
  176. 'request': self.get_headers().get('User-Agent')
  177. })
  178. else:
  179. request_user_agent.update(self._extra_user_agent)
  180. return CaseInsensitiveDict(request_user_agent)
  181. def set_location_service_code(self, location_service_code):
  182. self._location_service_code = location_service_code
  183. def get_location_service_code(self):
  184. return self._location_service_code
  185. def get_location_endpoint_type(self):
  186. return self._location_endpoint_type
  187. def set_content_type(self, content_type):
  188. self.add_header("Content-Type", content_type)
  189. @abc.abstractmethod
  190. def get_style(self):
  191. pass
  192. @abc.abstractmethod
  193. def get_url(self, region_id, ak, secret):
  194. pass
  195. @abc.abstractmethod
  196. def get_signed_header(self, region_id, ak, secret):
  197. pass
  198. def set_endpoint(self, endpoint):
  199. self.endpoint = endpoint
  200. def get_connect_timeout(self):
  201. return self._request_connect_timeout
  202. def set_connect_timeout(self, connect_timeout):
  203. self._request_connect_timeout = connect_timeout
  204. def get_read_timeout(self):
  205. return self._request_read_timeout
  206. def set_read_timeout(self, read_timeout):
  207. self._request_read_timeout = read_timeout
  208. class RpcRequest(AcsRequest):
  209. """
  210. Class to compose an RPC style request with.
  211. """
  212. def __init__(
  213. self,
  214. product,
  215. version,
  216. action_name,
  217. location_service_code=None,
  218. location_endpoint_type='openAPI',
  219. format=None,
  220. protocol=None,
  221. signer=sha_hmac1):
  222. AcsRequest.__init__(
  223. self,
  224. product,
  225. version,
  226. action_name,
  227. location_service_code,
  228. location_endpoint_type,
  229. format,
  230. protocol,
  231. mt.GET)
  232. self._style = STYLE_RPC
  233. self._signer = signer
  234. def get_style(self):
  235. return self._style
  236. def _get_sign_params(self):
  237. req_params = self.get_query_params()
  238. if req_params is None:
  239. req_params = {}
  240. req_params['Version'] = self.get_version()
  241. req_params['Action'] = self.get_action_name()
  242. req_params['Format'] = self.get_accept_format()
  243. return req_params
  244. def get_url(self, region_id, access_key_id, access_key_secret):
  245. sign_params = self._get_sign_params()
  246. if 'RegionId' not in iterkeys(sign_params):
  247. sign_params['RegionId'] = region_id
  248. url, string_to_sign = rpc_signer.get_signed_url(
  249. sign_params,
  250. access_key_id,
  251. access_key_secret,
  252. self.get_accept_format(),
  253. self.get_method(),
  254. self.get_body_params(),
  255. self._signer)
  256. self.string_to_sign = string_to_sign
  257. return url
  258. def get_signed_header(self, region_id=None, ak=None, secret=None):
  259. headers = {}
  260. for headerKey, headerValue in iteritems(self.get_headers()):
  261. if headerKey.startswith("x-acs-") or headerKey.startswith("x-sdk-"):
  262. headers[headerKey] = headerValue
  263. return headers
  264. class RoaRequest(AcsRequest):
  265. """
  266. Class to compose an ROA style request with.
  267. """
  268. def __init__(
  269. self,
  270. product,
  271. version,
  272. action_name,
  273. location_service_code=None,
  274. location_endpoint_type='openAPI',
  275. method=None,
  276. headers=None,
  277. uri_pattern=None,
  278. path_params=None,
  279. protocol=None):
  280. """
  281. :param product: String, mandatory
  282. :param version: String, mandatory
  283. :param action_name: String, mandatory
  284. :param method: String
  285. :param headers: Dict
  286. :param uri_pattern: String
  287. :param path_params: Dict
  288. :param protocol: String
  289. :return:
  290. """
  291. AcsRequest.__init__(
  292. self,
  293. product,
  294. version,
  295. action_name,
  296. location_service_code,
  297. location_endpoint_type,
  298. ft.RAW,
  299. protocol,
  300. method)
  301. self._style = STYLE_ROA
  302. self._method = method
  303. if headers is not None:
  304. self._header = headers
  305. self._uri_pattern = uri_pattern
  306. self._path_params = path_params
  307. def get_style(self):
  308. """
  309. :return: String
  310. """
  311. return self._style
  312. def get_path_params(self):
  313. return self._path_params
  314. def set_path_params(self, path_params):
  315. self._path_params = path_params
  316. def add_path_param(self, k, v):
  317. if self._path_params is None:
  318. self._path_params = {}
  319. self._path_params[k] = v
  320. def _get_sign_params(self):
  321. req_params = self.get_query_params()
  322. if req_params is None:
  323. req_params = {}
  324. self.add_header("x-acs-version", self.get_version())
  325. # req_params['Version'] = self.get_version()
  326. # req_params['Action'] = self.get_action_name()
  327. # req_params['Format'] = self.get_accept_format()
  328. return req_params
  329. def get_signed_header(self, region_id, ak, secret):
  330. """
  331. Generate signed header
  332. :param region_id: String
  333. :param ak: String
  334. :param secret: String
  335. :return: Dict
  336. """
  337. sign_params = self._get_sign_params()
  338. if self.get_content() is not None:
  339. self.add_header(
  340. 'Content-MD5', md5_sum(self.get_content()))
  341. if 'RegionId' not in sign_params.keys():
  342. sign_params['RegionId'] = region_id
  343. self.add_header('x-acs-region-id', str(region_id))
  344. signed_headers, sign_to_string = roa_signer.get_signature_headers(
  345. sign_params,
  346. ak,
  347. secret,
  348. self.get_accept_format(),
  349. self.get_headers(),
  350. self.get_uri_pattern(),
  351. self.get_path_params(),
  352. self.get_method())
  353. self.string_to_sign = sign_to_string
  354. return signed_headers
  355. def get_url(self, region_id, ak=None, secret=None):
  356. """
  357. Compose request url without domain
  358. :param region_id: String
  359. :return: String
  360. """
  361. sign_params = self.get_query_params()
  362. url = roa_signer.get_url(
  363. self.get_uri_pattern(),
  364. sign_params,
  365. self.get_path_params())
  366. return url
  367. class CommonRequest(AcsRequest):
  368. def __init__(self, domain=None, version=None, action_name=None, uri_pattern=None, product=None,
  369. location_endpoint_type='openAPI'):
  370. super(CommonRequest, self).__init__(product)
  371. self.request = None
  372. self.endpoint = domain
  373. self._version = version
  374. self._action_name = action_name
  375. self._uri_pattern = uri_pattern
  376. self._product = product
  377. self._location_endpoint_type = location_endpoint_type
  378. self._signer = sha_hmac1
  379. self.add_header('x-sdk-invoke-type', 'common')
  380. self._path_params = None
  381. self._method = "GET"
  382. def get_path_params(self):
  383. return self._path_params
  384. def set_path_params(self, path_params):
  385. self._path_params = path_params
  386. def add_path_param(self, k, v):
  387. if self._path_params is None:
  388. self._path_params = {}
  389. self._path_params[k] = v
  390. def set_domain(self, domain):
  391. self.endpoint = domain
  392. def get_domain(self):
  393. return self.endpoint
  394. def set_version(self, version):
  395. self._version = version
  396. def get_version(self):
  397. return self._version
  398. def set_action_name(self, action_name):
  399. self._action_name = action_name
  400. def get_action_name(self):
  401. return self._action_name
  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())