11
11
# License for the specific language governing permissions and limitations
12
12
# under the License.
13
13
14
+ import logging
14
15
import os
15
16
import sys
16
17
17
- import certifi
18
- import urllib3
18
+ import httpx
19
19
20
20
from gabbi .handlers import jsonhandler
21
21
from gabbi import utils
22
22
23
- # Disable SSL warnings otherwise tests which process stderr will get
24
- # extra information.
25
- urllib3 .disable_warnings ()
23
+ logging .getLogger ('httpx' ).setLevel (logging .WARNING )
26
24
27
25
28
- class Http ( urllib3 . PoolManager ) :
29
- """A subclass of the ``urllib3.PoolManager`` to munge the data .
26
+ class Http :
27
+ """A class to munge the HTTP response .
30
28
31
29
This transforms the response to look more like what httplib2
32
30
provided when it was used as the HTTP client.
33
31
"""
34
32
33
+ def __init__ (self , ** kwargs ):
34
+ self .extensions = {}
35
+ if 'server_hostname' in kwargs :
36
+ self .extensions ['sni_hostname' ] = kwargs ['server_hostname' ]
37
+ self .client = httpx .Client (verify = kwargs .get ('cert_validate' , True ))
38
+
35
39
def request (self , absolute_uri , method , body , headers , redirect , timeout ):
36
- if redirect :
37
- retry = urllib3 .util .Retry (raise_on_redirect = False , redirect = 5 )
38
- else :
39
- retry = urllib3 .util .Retry (total = False , redirect = False )
40
- response = super (Http , self ).request (
41
- method ,
42
- absolute_uri ,
43
- body = body ,
44
- headers = headers ,
45
- retries = retry ,
46
- timeout = timeout ,
47
- )
40
+ try :
41
+ response = self .client .request (
42
+ method = method ,
43
+ url = absolute_uri ,
44
+ headers = headers ,
45
+ content = body ,
46
+ timeout = timeout ,
47
+ follow_redirects = redirect ,
48
+ extensions = self .extensions ,
49
+ )
50
+ except httpx .ConnectError as error :
51
+ raise RuntimeError (
52
+ f'{ error } .\n \n Method: { method } \n URL: { absolute_uri } '
53
+ ) from error
48
54
49
55
# Transform response into something akin to httplib2
50
56
# response object.
51
- content = response .data
52
- status = response .status
53
- reason = response .reason
57
+ content = response .content
58
+ status = response .status_code
59
+ reason = response .reason_phrase
60
+ http_version = response .http_version
54
61
headers = response .headers
55
62
headers ['status' ] = str (status )
56
- headers ['reason' ] = reason
63
+ headers ['reason' ] = str (reason )
64
+ headers ['http_protocol_version' ] = str (http_version )
57
65
58
- # Shut down open PoolManagers whose connections have completed to
59
- # save on socket file descriptors.
60
- self .clear ()
61
66
return headers , content
62
67
63
68
@@ -87,6 +92,7 @@ class VerboseHttp(Http):
87
92
HEADER_BLACKLIST = [
88
93
'status' ,
89
94
'reason' ,
95
+ 'http_protocol_version' ,
90
96
]
91
97
92
98
REQUEST_PREFIX = '>'
@@ -106,27 +112,26 @@ def __init__(self, **kwargs):
106
112
self ._stream = kwargs .pop ('stream' )
107
113
if self ._use_color :
108
114
self .colorize = utils .get_colorizer (self ._stream )
109
- super (VerboseHttp , self ).__init__ (** kwargs )
115
+ super ().__init__ (** kwargs )
110
116
111
117
def request (self , absolute_uri , method , body , headers , redirect , timeout ):
112
118
"""Display request parameters before requesting."""
113
119
114
- self ._verbose_output ('#### %s ####' % self . caption ,
120
+ self ._verbose_output (f '#### { self . caption } ####' ,
115
121
color = self .COLORMAP ['caption' ])
116
- self ._verbose_output ('%s %s' % ( method , absolute_uri ) ,
122
+ self ._verbose_output (f' { method } { absolute_uri } ' ,
117
123
prefix = self .REQUEST_PREFIX ,
118
124
color = self .COLORMAP ['request' ])
119
125
120
126
self ._print_headers (headers , prefix = self .REQUEST_PREFIX )
121
127
self ._print_body (headers , body )
122
128
123
- response , content = super (VerboseHttp , self ).request (
129
+ response , content = super ().request (
124
130
absolute_uri , method , body , headers , redirect , timeout )
125
131
126
132
# Blank line for division
127
133
self ._verbose_output ('' )
128
- self ._verbose_output ('%s %s' % (response ['status' ],
129
- response ['reason' ]),
134
+ self ._verbose_output (f'{ response ["status" ]} { response ["reason" ]} ' ,
130
135
prefix = self .RESPONSE_PREFIX ,
131
136
color = self .COLORMAP ['status' ])
132
137
self ._print_headers (response , prefix = self .RESPONSE_PREFIX )
@@ -172,8 +177,8 @@ def _print_body(self, headers, content):
172
177
173
178
def _print_header (self , name , value , prefix = '' , stream = None ):
174
179
"""Output one single header."""
175
- header = self .colorize (self .COLORMAP ['header' ], "%s:" % name )
176
- self ._verbose_output ("%s %s" % ( header , value ) , prefix = prefix ,
180
+ header = self .colorize (self .COLORMAP ['header' ], f' { name } :' )
181
+ self ._verbose_output (f' { header } { value } ' , prefix = prefix ,
177
182
stream = stream )
178
183
179
184
def _verbose_output (self , message , prefix = '' , color = None , stream = None ):
@@ -194,29 +199,23 @@ def get_http(
194
199
timeout = 30 ,
195
200
):
196
201
"""Return an ``Http`` class for making requests."""
197
- cert_validation = {'cert_reqs' : 'CERT_NONE' } if not cert_validate else {}
198
-
199
202
if not verbose :
200
203
return Http (
201
- strict = True ,
202
- ca_certs = certifi .where (),
203
204
server_hostname = hostname ,
204
205
timeout = timeout ,
205
- ** cert_validation
206
+ cert_validate = cert_validate ,
206
207
)
207
208
208
- headers = False if verbose == 'body' else True
209
- body = False if verbose == 'headers' else True
209
+ headers = verbose != 'body'
210
+ body = verbose != 'headers'
210
211
211
212
return VerboseHttp (
212
213
headers = headers ,
213
214
body = body ,
214
215
stream = sys .stdout ,
215
216
caption = caption ,
216
217
colorize = True ,
217
- strict = True ,
218
- ca_certs = certifi .where (),
219
218
server_hostname = hostname ,
220
219
timeout = timeout ,
221
- ** cert_validation
220
+ cert_validate = cert_validate ,
222
221
)
0 commit comments