27
27
except ImportError :
28
28
urlfetch , urlfetch_errors = None , None
29
29
30
+ try :
31
+ import urllib3 # type: ignore
32
+ except ImportError :
33
+ urllib3 = None
34
+
30
35
# datadog
31
36
from datadog .api .exceptions import ProxyError , ClientError , HTTPError , HttpTimeout
32
37
@@ -178,6 +183,58 @@ def raise_on_status(cls, result):
178
183
raise HTTPError (status_code )
179
184
180
185
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
+ retries = max_retries ,
205
+ timeout = timeout ,
206
+ cert_reqs = "CERT_REQUIRED" if verify else "CERT_NONE" ,
207
+ )
208
+
209
+ newheaders = copy .deepcopy (headers )
210
+ newheaders ["User-Agent" ] = _get_user_agent_header ()
211
+ response = cls ._pool .request (
212
+ method , url , body = data , fields = params , headers = newheaders
213
+ )
214
+ cls .raise_on_status (response )
215
+
216
+ except urllib3 .exceptions .ProxyError as e :
217
+ raise _remove_context (ProxyError (method , url , e ))
218
+ except urllib3 .exceptions .MaxRetryError as e :
219
+ raise _remove_context (ClientError (method , url , e ))
220
+ except urllib3 .exceptions .TimeoutError as e :
221
+ raise _remove_context (HttpTimeout (method , url , e ))
222
+ except urllib3 .exceptions .HTTPError as e :
223
+ raise _remove_context (HTTPError (e ))
224
+
225
+ return response
226
+
227
+ @classmethod
228
+ def raise_on_status (cls , response ):
229
+ """
230
+ Raise on HTTP status code errors.
231
+ """
232
+ status_code = response .status
233
+ if status_code < 200 or status_code >= 300 :
234
+ if status_code not in (400 , 401 , 403 , 404 , 409 , 429 ):
235
+ raise HTTPError (status_code , response .reason )
236
+
237
+
181
238
def resolve_http_client ():
182
239
"""
183
240
Resolve an appropriate HTTP client based the defined priority and user environment.
@@ -190,6 +247,10 @@ def resolve_http_client():
190
247
log .debug (u"Use `urlfetch` based HTTP client." )
191
248
return URLFetchClient
192
249
250
+ if urllib3 :
251
+ log .debug (u"Use `urllib3` based HTTP client." )
252
+ return Urllib3Client
253
+
193
254
raise ImportError (
194
255
u"Datadog API client was unable to resolve a HTTP client. " u" Please install `requests` library."
195
256
)
0 commit comments