2424
2525import re
2626import base64
27- import gzip
28- import urllib .request
29- import urllib .error
27+ import httpx
3028from urllib .error import HTTPError , URLError
29+ from io import BytesIO
3130
3231from typing import Union
3332from urllib .parse import unquote
3433
3534
36- """
37- Default encoding
38- """
39- _DEFAULT_ENCODING = "utf-8"
40-
4135_URL_REGEX = re .compile (
4236 r'^((?:http)s?)://' # http:// or https://
4337 # basic authentication -> username:password@
@@ -86,46 +80,32 @@ def __init__(self, url, headers={}, method=None):
8680
8781 self .url = url_addr
8882 self .headers = headers or {}
89- self .method = method
83+ self .method = method or "GET"
84+ self .content = None
9085
9186 if url_auth is not None :
9287 self .headers ['Authorization' ] = f'Basic { url_auth } '
9388
9489 def add_header (self , key : str , value : str ):
9590 self .headers [key ] = value
9691
97- def _to_urllib_request (self ):
98- return urllib . request . Request (self .url , headers = self .headers , method = self .method )
92+ def _to_httpx_request (self ) -> httpx . Request :
93+ return httpx . Request (self .method , self . url , headers = self .headers , content = self .content )
9994
10095
10196class HttpResponse :
10297
10398 def __init__ (self , raw_response = None ) -> None :
104- self .raw_response = raw_response
105- self .__body_read = False
106- self .__body_text = ''
107-
108- def _read_body (self ):
109- res = self .raw_response
110- if res .info ().get ("Content-Encoding" ) == "gzip" :
111- f = gzip .GzipFile (fileobj = res )
112- else :
113- f = res
114- body_text = f .read ().decode (_DEFAULT_ENCODING )
115- f .close ()
116- return body_text
99+ self .raw_response : httpx .Response = raw_response
100+ self .__body_text = self .raw_response .text if self .raw_response else ''
117101
118102 @property
119- def body_text (self ):
120- if not self .__body_read :
121- self .__body_text = self ._read_body ()
122- self .__body_read = True
103+ def body_text (self ) -> str :
123104 return self .__body_text
124105
125106 @body_text .setter
126- def body_text (self , val ):
127- self .__body_text = val
128- self .__body_read = True
107+ def body_text (self , value ) -> None :
108+ self .__body_text = value
129109
130110
131111class HttpClient :
@@ -135,14 +115,25 @@ async def urlopen(self, request: Union[str, HttpRequest] = None,
135115 if isinstance (request , HttpRequest ):
136116 req = request
137117 elif isinstance (request , str ):
138- req = HttpRequest (request , headers = { 'Accept-Encoding' : 'gzip' } )
118+ req = HttpRequest (request )
139119 else :
140120 raise URLError ("Invalid URL" )
141121
142- req = req ._to_urllib_request ()
122+ if data is not None :
123+ req .content = data
124+
143125 req .add_header ("Connection" , "close" )
144- res = urllib .request .urlopen (req , data = data , timeout = timeout )
145- return HttpResponse (res )
126+ req .add_header ("Accept-Encoding" , "gzip, deflate" )
127+
128+ try :
129+ async with httpx .AsyncClient (timeout = timeout , follow_redirects = True ) as client :
130+ res = await client .send (req ._to_httpx_request ())
131+ res .raise_for_status ()
132+ return HttpResponse (res )
133+ except httpx .HTTPStatusError as e :
134+ raise HTTPError (e .request .url , e .response .status_code , str (e ), e .response .headers , BytesIO (e .response .content )) from e
135+ except httpx .RequestError as e :
136+ raise URLError (str (e )) from e
146137
147138
148139http_client = HttpClient ()
0 commit comments