@@ -8,6 +8,9 @@ def __init__(self, reader):
8
8
def read (self , sz = - 1 ):
9
9
return (yield from self .content .read (sz ))
10
10
11
+ def text (self , sz = - 1 ):
12
+ return self .read (sz = sz )
13
+
11
14
def __repr__ (self ):
12
15
return "<ClientResponse %d %s>" % (self .status , self .headers )
13
16
@@ -40,22 +43,139 @@ def __repr__(self):
40
43
return "<ChunkedClientResponse %d %s>" % (self .status , self .headers )
41
44
42
45
46
+ class _RequestContextManager :
47
+ def __init__ (self , client , request_co ):
48
+ self .reqco = request_co
49
+ self .client = client
50
+
51
+ async def __aenter__ (self ):
52
+ return await self .reqco
53
+
54
+ async def __aexit__ (self , * args ):
55
+ await self .client ._reader .aclose ()
56
+ return await asyncio .sleep (0 )
57
+
58
+
59
+ class ClientSession :
60
+ def __init__ (self ):
61
+ self ._reader = None
62
+
63
+ async def __aenter__ (self ):
64
+ return self
65
+
66
+ async def __aexit__ (self , * args ):
67
+ return await asyncio .sleep (0 )
68
+
69
+ def request (self , method , url , ssl = None ):
70
+ return _RequestContextManager (self , self ._request (method , url , ssl = ssl ))
71
+
72
+ async def _request (self , method , url , ssl = None ):
73
+ redir_cnt = 0
74
+ redir_url = None
75
+ while redir_cnt < 2 :
76
+ reader = yield from self .request_raw (method , url , ssl )
77
+ headers = []
78
+ sline = yield from reader .readline ()
79
+ sline = sline .split (None , 2 )
80
+ status = int (sline [1 ])
81
+ chunked = False
82
+ while True :
83
+ line = yield from reader .readline ()
84
+ if not line or line == b"\r \n " :
85
+ break
86
+ headers .append (line )
87
+ if line .startswith (b"Transfer-Encoding:" ):
88
+ if b"chunked" in line :
89
+ chunked = True
90
+ elif line .startswith (b"Location:" ):
91
+ url = line .rstrip ().split (None , 1 )[1 ].decode ("latin-1" )
92
+
93
+ if 301 <= status <= 303 :
94
+ redir_cnt += 1
95
+ yield from reader .aclose ()
96
+ continue
97
+ break
98
+
99
+ if chunked :
100
+ resp = ChunkedClientResponse (reader )
101
+ else :
102
+ resp = ClientResponse (reader )
103
+ resp .status = status
104
+ resp .headers = headers
105
+ self ._reader = reader
106
+ return resp
107
+
108
+ async def request_raw (self , method , url , ssl = None ):
109
+ try :
110
+ proto , dummy , host , path = url .split ("/" , 3 )
111
+ except ValueError :
112
+ proto , dummy , host = url .split ("/" , 2 )
113
+ path = ""
114
+
115
+ if proto == "http:" :
116
+ port = 80
117
+ elif proto == "https:" :
118
+ port = 443
119
+ if ssl is None :
120
+ ssl = True
121
+ else :
122
+ raise ValueError ("Unsupported protocol: " + proto )
123
+
124
+ if ":" in host :
125
+ host , port = host .split (":" , 1 )
126
+ port = int (port )
127
+
128
+ reader , writer = yield from asyncio .open_connection (host , port , ssl = ssl )
129
+ # Use protocol 1.0, because 1.1 always allows to use chunked transfer-encoding
130
+ # But explicitly set Connection: close, even though this should be default for 1.0,
131
+ # 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 ,
138
+ )
139
+ )
140
+ yield from writer .awrite (query .encode ("latin-1" ))
141
+ # yield from writer.aclose()
142
+ return reader
143
+
144
+ def get (self , url , ssl = None ):
145
+ return _RequestContextManager (self , self ._request ("GET" , url , ssl = ssl ))
146
+
147
+
43
148
def request_raw (method , url ):
44
149
try :
45
150
proto , dummy , host , path = url .split ("/" , 3 )
46
151
except ValueError :
47
152
proto , dummy , host = url .split ("/" , 2 )
48
153
path = ""
49
- if proto != "http:" :
154
+
155
+ if proto == "http:" :
156
+ port = 80
157
+ elif proto == "https:" :
158
+ port = 443
159
+ else :
50
160
raise ValueError ("Unsupported protocol: " + proto )
51
- reader , writer = yield from asyncio .open_connection (host , 80 )
161
+
162
+ if ":" in host :
163
+ host , port = host .split (":" , 1 )
164
+ port = int (port )
165
+
166
+ reader , writer = yield from asyncio .open_connection (
167
+ host , port , ssl = proto == "https:"
168
+ )
52
169
# Use protocol 1.0, because 1.1 always allows to use chunked transfer-encoding
53
170
# But explicitly set Connection: close, even though this should be default for 1.0,
54
171
# because some servers misbehave w/o it.
55
- query = "%s /%s HTTP/1.0\r \n Host: %s\r \n Connection: close\r \n User-Agent: compat\r \n \r \n " % (
56
- method ,
57
- path ,
58
- host ,
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
+ )
59
179
)
60
180
yield from writer .awrite (query .encode ("latin-1" ))
61
181
# yield from writer.aclose()
0 commit comments