Skip to content
This repository was archived by the owner on Nov 22, 2024. It is now read-only.

Commit 8c53a8a

Browse files
committed
openapi url now in code where it belongs, args checked for type str, logging messgaes for various errors, http error code 400 & 429 handled
1 parent 53af1a2 commit 8c53a8a

1 file changed

Lines changed: 46 additions & 5 deletions

File tree

CloudFlare/cloudflare.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from .exceptions import CloudFlareError, CloudFlareAPIError, CloudFlareInternalError
1515

1616
BASE_URL = 'https://api.cloudflare.com/client/v4'
17+
OPENAPI_URL = 'https://github.com/cloudflare/api-schemas/raw/main/openapi.json'
1718

1819
DEFAULT_GLOBAL_REQUEST_TIMEOUT = 5
1920
DEFAULT_MAX_REQUEST_RETRIES = 5
@@ -38,6 +39,9 @@ def __init__(self, config):
3839
# We must have a base_url value
3940
self.base_url = config['base_url'] if 'base_url' in config else BASE_URL
4041

42+
# The modern-day API definition comes from here (soon)
43+
self.openapi_url = config['openapi_url'] if 'openapi_url' in config else OPENAPI_URL
44+
4145
self.raw = config['raw']
4246
self.use_sessions = config['use_sessions']
4347
self.global_request_timeout = config['global_request_timeout'] if 'global_request_timeout' in config else DEFAULT_GLOBAL_REQUEST_TIMEOUT
@@ -119,12 +123,18 @@ def _add_auth_headers(self, method):
119123
api_token = self.config[v] if v in self.config else self.api_token
120124

121125
if api_email is None and api_key is None and api_token is None:
126+
if self.logger:
127+
self.logger.debug('neither email/key or token defined')
122128
raise CloudFlareAPIError(0, 'neither email/key or token defined')
123129

124130
if api_key is not None and api_token is not None:
131+
if self.logger:
132+
self.logger.debug('confused info - both key and token defined')
125133
raise CloudFlareAPIError(0, 'confused info - both key and token defined')
126134

127135
if api_email is not None and api_key is None and api_token is None:
136+
if self.logger:
137+
self.logger.debug('email defined however neither key or token defined')
128138
raise CloudFlareAPIError(0, 'email defined however neither key or token defined')
129139

130140
# We know at this point that at-least one api_* is set and no confusion!
@@ -156,14 +166,18 @@ def _add_certtoken_headers(self, method):
156166
api_certtoken = self.api_certtoken # use generic value for all methods
157167

158168
if api_certtoken is None:
169+
if self.logger:
170+
self.logger.debug('no cert token defined')
159171
raise CloudFlareAPIError(0, 'no cert token defined')
160172
self.headers['X-Auth-User-Service-Key'] = api_certtoken
161173

162174
def do_not_available(self, method, parts, identifiers, params=None, data=None, content_type=None, files=None):
163175
""" Cloudflare v4 API"""
164176

165177
# base class simply returns not available - no processing of any arguments
166-
raise CloudFlareAPIError(0, 'call not available')
178+
if self.logger:
179+
self.logger.debug('call for this method not available')
180+
raise CloudFlareAPIError(0, 'call for this method not available')
167181

168182
def do_no_auth(self, method, parts, identifiers, params=None, data=None, content_type=None, files=None):
169183
""" Cloudflare v4 API"""
@@ -305,8 +319,24 @@ def _call_network(self, method, headers, parts, identifiers, params, data_str, d
305319
else:
306320
self.logger.debug('Response: %d, %s, %s', response_code, response_type, '...')
307321

308-
if response_code == 500:
322+
if response_code == 429:
323+
# 429 Too Many Requests
324+
# The HTTP 429 Too Many Requests response status code indicates the user
325+
# has sent too many requests in a given amount of time ("rate limiting").
326+
# A Retry-After header might be included to this response indicating how
327+
# long to wait before making a new request.
328+
try:
329+
retry_after = response.headers['Retry-After']
330+
except (KeyError,IndexError):
331+
retry_after = ''
332+
# XXX/TODO no processing for now - but could try again within library
333+
if self.logger:
334+
self.logger.debug('Response: 429 Header Retry-After: %s', retry_after)
335+
336+
# if (response_code >= 400 and response_code <= 499) or response_code == 500:
337+
if response_code in [400,500]:
309338
# The /certificates API call insists on a 500 error return and yet has valid error data
339+
# Other API calls can return 400 or 4xx with valid response data
310340
# lets check and convert if able
311341
try:
312342
j = json.loads(response_data)
@@ -317,7 +347,7 @@ def _call_network(self, method, headers, parts, identifiers, params, data_str, d
317347
# yippe - try to continue by allowing to process fully
318348
response_code = 200
319349
except:
320-
# ignore - maybe a real 500!
350+
# ignore - maybe a real error, let proceed!
321351
pass
322352

323353
if response_code >= 500 and response_code <= 599:
@@ -571,9 +601,11 @@ def _call_unwrapped(self, method, parts, identifiers, params, data_str, data_jso
571601
result = response_data
572602
return result
573603

574-
def api_from_openapi(self, url):
604+
def api_from_openapi(self, url=None):
575605
""" Cloudflare v4 API"""
576606

607+
if url is None:
608+
url = self.openapi_url
577609
return self._read_from_web(url)
578610

579611
def _read_from_web(self, url):
@@ -825,7 +857,7 @@ def _api_list(self, m=None, s=''):
825857
#
826858
# return api_decode_from_web(self._base.api_from_web())
827859

828-
def api_from_openapi(self, url):
860+
def api_from_openapi(self, url=None):
829861
""" Cloudflare v4 API"""
830862

831863
return api_decode_from_openapi(self._base.api_from_openapi(url))
@@ -835,6 +867,15 @@ def __init__(self, email=None, key=None, token=None, certtoken=None, debug=False
835867

836868
self._base = None
837869

870+
if email and not isinstance(email, str):
871+
raise TypeError('email must be str')
872+
if key and not isinstance(key, str):
873+
raise TypeError('key must be str')
874+
if token and not isinstance(token, str):
875+
raise TypeError('token must be str')
876+
if certtoken and not isinstance(certtoken, str):
877+
raise TypeError('certtoken must be str')
878+
838879
try:
839880
config = read_configs(profile)
840881
except Exception as e:

0 commit comments

Comments
 (0)