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