1
1
import uasyncio as asyncio
2
+ import json as _json
2
3
3
4
4
5
class ClientResponse :
@@ -11,6 +12,9 @@ def read(self, sz=-1):
11
12
def text (self , sz = - 1 ):
12
13
return self .read (sz = sz )
13
14
15
+ async def json (self ):
16
+ return _json .loads (await self .read ())
17
+
14
18
def __repr__ (self ):
15
19
return "<ClientResponse %d %s>" % (self .status , self .headers )
16
20
@@ -57,23 +61,27 @@ async def __aexit__(self, *args):
57
61
58
62
59
63
class ClientSession :
60
- def __init__ (self ):
64
+ def __init__ (self , base_url = "" ):
61
65
self ._reader = None
66
+ self ._base_url = base_url
62
67
63
68
async def __aenter__ (self ):
64
69
return self
65
70
66
71
async def __aexit__ (self , * args ):
67
72
return await asyncio .sleep (0 )
68
73
69
- def request (self , method , url , ssl = None ):
70
- return _RequestContextManager (self , self ._request (method , url , ssl = ssl ))
74
+ def request (self , method , url , data = None , json = None , ssl = None ):
75
+ return _RequestContextManager (
76
+ self ,
77
+ self ._request (method , self ._base_url + url , data = data , json = json , ssl = ssl ),
78
+ )
71
79
72
- async def _request (self , method , url , ssl = None ):
80
+ async def _request (self , method , url , data = None , json = None , ssl = None ):
73
81
redir_cnt = 0
74
82
redir_url = None
75
83
while redir_cnt < 2 :
76
- reader = yield from self .request_raw (method , url , ssl )
84
+ reader = yield from self .request_raw (method , url , data , json , ssl )
77
85
headers = []
78
86
sline = yield from reader .readline ()
79
87
sline = sline .split (None , 2 )
@@ -105,7 +113,11 @@ async def _request(self, method, url, ssl=None):
105
113
self ._reader = reader
106
114
return resp
107
115
108
- async def request_raw (self , method , url , ssl = None ):
116
+ async def request_raw (self , method , url , data = None , json = None , ssl = None ):
117
+ if json and isinstance (json , dict ):
118
+ data = _json .dumps (json )
119
+ if data is not None and method == "GET" :
120
+ method = "POST"
109
121
try :
110
122
proto , dummy , host , path = url .split ("/" , 3 )
111
123
except ValueError :
@@ -129,20 +141,70 @@ async def request_raw(self, method, url, ssl=None):
129
141
# Use protocol 1.0, because 1.1 always allows to use chunked transfer-encoding
130
142
# But explicitly set Connection: close, even though this should be default for 1.0,
131
143
# because some servers misbehave w/o it.
132
- query = (
133
- "%s /%s HTTP/1.0\r \n Host: %s\r \n Connection: close\r \n User-Agent: compat\r \n \r \n "
134
- % (
135
- method ,
136
- path ,
137
- host ,
144
+ if not data :
145
+ query = (
146
+ "%s /%s HTTP/1.0\r \n Host: %s\r \n Connection: close\r \n User-Agent: compat\r \n \r \n "
147
+ % (
148
+ method ,
149
+ path ,
150
+ host ,
151
+ )
138
152
)
139
- )
153
+ else :
154
+ query = (
155
+ """%s /%s HTTP/1.0\r \n Host: %s\r \n %sContent-Length: %s\r \n \r \n %s\r \n Connection: close\r \n User-Agent: compat\r \n \r \n """
156
+ % (
157
+ method ,
158
+ path ,
159
+ host ,
160
+ "Content-Type: application/json\r \n " if json else "" ,
161
+ str (len (str (data ))),
162
+ data ,
163
+ )
164
+ )
165
+
140
166
yield from writer .awrite (query .encode ("latin-1" ))
141
167
# yield from writer.aclose()
142
168
return reader
143
169
144
170
def get (self , url , ssl = None ):
145
- return _RequestContextManager (self , self ._request ("GET" , url , ssl = ssl ))
171
+ return _RequestContextManager (self , self ._request ("GET" , self ._base_url + url , ssl = ssl ))
172
+
173
+ def post (self , url , data = None , json = None , ssl = None ):
174
+ return _RequestContextManager (
175
+ self ,
176
+ self ._request ("POST" , self ._base_url + url , data = data , json = json , ssl = ssl ),
177
+ )
178
+
179
+ def put (self , url , data = None , json = None , ssl = None ):
180
+ return _RequestContextManager (
181
+ self ,
182
+ self ._request ("PUT" , self ._base_url + url , data = data , json = json , ssl = ssl ),
183
+ )
184
+
185
+ def patch (self , url , data = None , json = None , ssl = None ):
186
+ return _RequestContextManager (
187
+ self ,
188
+ self ._request ("PATCH" , self ._base_url + url , data = data , json = json , ssl = ssl ),
189
+ )
190
+
191
+ def delete (self , url , ssl = None ):
192
+ return _RequestContextManager (
193
+ self ,
194
+ self ._request ("DELETE" , self ._base_url + url , ssl = ssl ),
195
+ )
196
+
197
+ def head (self , url , ssl = None ):
198
+ return _RequestContextManager (
199
+ self ,
200
+ self ._request ("HEAD" , self ._base_url + url , ssl = ssl ),
201
+ )
202
+
203
+ def options (self , url , ssl = None ):
204
+ return _RequestContextManager (
205
+ self ,
206
+ self ._request ("OPTIONS" , self ._base_url + url , ssl = ssl ),
207
+ )
146
208
147
209
148
210
def request_raw (method , url ):
@@ -163,19 +225,14 @@ def request_raw(method, url):
163
225
host , port = host .split (":" , 1 )
164
226
port = int (port )
165
227
166
- reader , writer = yield from asyncio .open_connection (
167
- host , port , ssl = proto == "https:"
168
- )
228
+ reader , writer = yield from asyncio .open_connection (host , port , ssl = proto == "https:" )
169
229
# Use protocol 1.0, because 1.1 always allows to use chunked transfer-encoding
170
230
# But explicitly set Connection: close, even though this should be default for 1.0,
171
231
# because some servers misbehave w/o it.
172
- query = (
173
- "%s /%s HTTP/1.0\r \n Host: %s\r \n Connection: close\r \n User-Agent: compat\r \n \r \n "
174
- % (
175
- method ,
176
- path ,
177
- host ,
178
- )
232
+ query = "%s /%s HTTP/1.0\r \n Host: %s\r \n Connection: close\r \n User-Agent: compat\r \n \r \n " % (
233
+ method ,
234
+ path ,
235
+ host ,
179
236
)
180
237
yield from writer .awrite (query .encode ("latin-1" ))
181
238
# yield from writer.aclose()
0 commit comments