Skip to content

Commit cf7b603

Browse files
committed
Provide urllib3 implementation of HTTPClient.
1 parent d375ea0 commit cf7b603

File tree

1 file changed

+59
-0
lines changed

1 file changed

+59
-0
lines changed

datadog/api/http_client.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
except ImportError:
2828
urlfetch, urlfetch_errors = None, None
2929

30+
try:
31+
import urllib3
32+
except ImportError:
33+
urllib3 = None
34+
3035
# datadog
3136
from datadog.api.exceptions import ProxyError, ClientError, HTTPError, HttpTimeout
3237

@@ -178,6 +183,56 @@ def raise_on_status(cls, result):
178183
raise HTTPError(status_code)
179184

180185

186+
class Urllib3Client(HTTPClient):
187+
"""
188+
HTTP client based on 3rd party `urllib3` module.
189+
"""
190+
191+
_pool = None
192+
_pool_lock = Lock()
193+
194+
@classmethod
195+
def request(cls, method, url, headers, params, data, timeout, proxies, verify, max_retries):
196+
"""
197+
Wrapper around `urllib3.PoolManager.request` method. This method will raise
198+
exceptions for HTTP status codes that are not 2xx.
199+
"""
200+
try:
201+
with cls._pool_lock:
202+
if cls._pool is None:
203+
cls._pool = urllib3.PoolManager(
204+
timeout=timeout,
205+
retries=urllib3.util.retry.Retry(total=max_retries, backoff_factor=0.1),
206+
cert_reqs="CERT_REQUIRED" if verify else "CERT_NONE",
207+
)
208+
209+
response = cls._pool.request(
210+
method, url, body=data, fields=params, headers=headers, timeout=timeout, retries=max_retries,
211+
)
212+
cls.raise_on_status(response)
213+
214+
except urllib3.exceptions.ProxyError as e:
215+
raise _remove_context(ProxyError(method, url, e))
216+
except urllib3.exceptions.MaxRetryError as e:
217+
raise _remove_context(ClientError(method, url, e))
218+
except urllib3.exceptions.TimeoutError as e:
219+
raise _remove_context(HttpTimeout(method, url, e))
220+
except urllib3.exceptions.HTTPError as e:
221+
raise _remove_context(HTTPError(e))
222+
223+
return response
224+
225+
@classmethod
226+
def raise_on_status(cls, response):
227+
"""
228+
Raise on HTTP status code errors.
229+
"""
230+
status_code = response.status
231+
if status_code < 200 or status_code >= 300:
232+
if status_code not in (400, 401, 403, 404, 409, 429):
233+
raise HTTPError(status_code, response.reason)
234+
235+
181236
def resolve_http_client():
182237
"""
183238
Resolve an appropriate HTTP client based the defined priority and user environment.
@@ -190,6 +245,10 @@ def resolve_http_client():
190245
log.debug(u"Use `urlfetch` based HTTP client.")
191246
return URLFetchClient
192247

248+
if urllib3:
249+
log.debug(u"Use `urllib3` based HTTP client.")
250+
return Urllib3Client
251+
193252
raise ImportError(
194253
u"Datadog API client was unable to resolve a HTTP client. " u" Please install `requests` library."
195254
)

0 commit comments

Comments
 (0)