1
2
3
4
5
6 import re
7 import urlparse
8
9 try:
10 from cStringIO import StringIO
11 except ImportError:
12 from StringIO import StringIO
13
14 from restkit.http.body import ChunkedReader, LengthReader, EOFReader, Body, \
15 GzipBody
16 from restkit.errors import InvalidHeader, InvalidHeaderName, NoMoreData, \
17 InvalidRequestLine, InvalidRequestMethod, InvalidHTTPVersion, InvalidHTTPStatus
18
33
34 - def get_data(self, unreader, buf, stop=False):
35 data = unreader.read()
36 if not data:
37 if stop:
38 raise StopIteration()
39 raise NoMoreData(buf.getvalue())
40 buf.write(data)
41
42 - def parse(self, unreader):
43 buf = StringIO()
44
45 self.get_data(unreader, buf, stop=True)
46
47
48 idx = buf.getvalue().find("\r\n")
49 while idx < 0:
50 self.get_data(unreader, buf)
51 idx = buf.getvalue().find("\r\n")
52 self.parse_first_line(buf.getvalue()[:idx])
53 rest = buf.getvalue()[idx+2:]
54 buf.truncate(0)
55 buf.write(rest)
56
57
58 pos = 0
59 idx = buf.getvalue().find("\r\n\r\n")
60 done = buf.getvalue()[:2] == "\r\n"
61 while idx < 0 and not done:
62 pos = buf.tell() - 4
63 self.get_data(unreader, buf)
64 idx = buf.getvalue()[pos:].find("\r\n\r\n")
65 done = buf.getvalue()[:2] == "\r\n"
66 if done:
67 self.unreader.unread(buf.getvalue()[2:])
68 return ""
69
70 end = pos + idx
71 self.headers = self.parse_headers(buf.getvalue()[:end])
72
73 ret = buf.getvalue()[end+4:]
74 buf.truncate(0)
75 return ret
76
78 raise NotImplementedError()
79
81 headers = []
82
83
84 lines = []
85 lines = [line + "\r\n" for line in data.split("\r\n")]
86
87
88
89 while len(lines):
90
91 curr = lines.pop(0)
92 if curr.find(":") < 0:
93 raise InvalidHeader(curr.strip())
94 name, value = curr.split(":", 1)
95 name = name.rstrip(" \t")
96 if self.hdrre.search(name.upper()):
97 raise InvalidHeaderName(name)
98 name, value = name.strip(), [value.lstrip()]
99
100
101 while len(lines) and lines[0].startswith((" ", "\t")):
102 value.append(lines.pop(0))
103 value = ''.join(value).rstrip()
104
105 headers.append((name, value))
106 return headers
107
108 - def set_body_reader(self):
109 chunked = False
110 clength = None
111
112 for (name, value) in self.headers:
113 if name.upper() == "CONTENT-LENGTH":
114 try:
115 clength = int(value)
116 except ValueError:
117 clength = None
118 elif name.upper() == "TRANSFER-ENCODING":
119 chunked = value.lower() == "chunked"
120 elif name.upper() == "CONTENT-ENCODING":
121 self.encoding = value.lower()
122
123 if clength is not None or chunked:
124 break
125
126 if chunked:
127 self.body = Body(ChunkedReader(self, self.unreader))
128 elif clength is not None:
129 self.body = Body(LengthReader(self, self.unreader, clength))
130 else:
131 self.body = Body(EOFReader(self, self.unreader))
132
134 for (h, v) in self.headers:
135 if h.lower() == "connection":
136 if v.lower().strip() == "close":
137 return True
138 elif v.lower().strip() == "keep-alive":
139 return False
140 return self.version <= (1, 0)
141
142
145 self.methre = re.compile("[A-Z0-9$-_.]{3,20}")
146 self.versre = re.compile("HTTP/(\d+).(\d+)")
147
148 self.method = None
149 self.uri = None
150 self.scheme = None
151 self.host = None
152 self.port = 80
153 self.path = None
154 self.query = None
155 self.fragment = None
156
157 super(Request, self).__init__(unreader)
158
160 bits = line.split(None, 2)
161 if len(bits) != 3:
162 raise InvalidRequestLine(line)
163
164
165 if not self.methre.match(bits[0]):
166 raise InvalidRequestMethod(bits[0])
167 self.method = bits[0].upper()
168
169
170 self.uri = bits[1]
171 parts = urlparse.urlparse(bits[1])
172 self.scheme = parts.scheme or None
173 self.host = parts.netloc or None
174 if parts.port is None:
175 self.port = 80
176 else:
177 self.host = self.host.rsplit(":", 1)[0]
178 self.port = parts.port
179 self.path = parts.path or None
180 self.query = parts.query or None
181 self.fragment = parts.fragment or None
182
183
184 match = self.versre.match(bits[2])
185 if match is None:
186 raise InvalidHTTPVersion(bits[2])
187 self.version = (int(match.group(1)), int(match.group(2)))
188
189 - def set_body_reader(self):
190 super(Request, self).set_body_reader()
191 if isinstance(self.body.reader, EOFReader):
192 self.body = Body(LengthReader(self, self.unreader, 0))
193
195
197 self.versre = re.compile("HTTP/(\d+).(\d+)")
198 self.stare = re.compile("(\d{3})\s*(\w*)")
199 self.status = None
200 self.reason = None
201 self.status_int = None
202
203 super(Response, self).__init__(unreader)
204
206 bits = line.split(None, 1)
207 if len(bits) != 2:
208 raise InvalidRequestLine(line)
209
210
211 matchv = self.versre.match(bits[0])
212 if matchv is None:
213 raise InvalidHTTPVersion(bits[0])
214 self.version = (int(matchv.group(1)), int(matchv.group(2)))
215
216
217 matchs = self.stare.match(bits[1])
218 if matchs is None:
219 raise InvalidHTTPStatus(bits[1])
220
221 self.status = bits[1]
222 self.status_int = int(matchs.group(1))
223 self.reason = matchs.group(2)
224
225 - def set_body_reader(self):
226 super(Response, self).set_body_reader()
227 if self.encoding == "gzip":
228 self.body = GzipBody(self.body.reader)
229