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, DeflateBody
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 idx = buf.getvalue().find("\r\n\r\n")
59 done = buf.getvalue()[:2] == "\r\n"
60 while idx < 0 and not done:
61 self.get_data(unreader, buf)
62 idx = buf.getvalue().find("\r\n\r\n")
63 done = buf.getvalue()[:2] == "\r\n"
64 if done:
65 self.unreader.unread(buf.getvalue()[2:])
66 return ""
67
68 self.headers = self.parse_headers(buf.getvalue()[:idx])
69
70 ret = buf.getvalue()[idx+4:]
71 buf.truncate(0)
72 return ret
73
75 raise NotImplementedError()
76
78 headers = []
79
80
81 lines = []
82 lines = [line + "\r\n" for line in data.split("\r\n")]
83
84
85
86 while len(lines):
87
88 curr = lines.pop(0)
89 if curr.find(":") < 0:
90 raise InvalidHeader(curr.strip())
91 name, value = curr.split(":", 1)
92 name = name.rstrip(" \t")
93 if self.hdrre.search(name.upper()):
94 raise InvalidHeaderName(name)
95 name, value = name.strip(), [value.lstrip()]
96
97
98 while len(lines) and lines[0].startswith((" ", "\t")):
99 value.append(lines.pop(0))
100 value = ''.join(value).rstrip()
101
102 headers.append((name, value))
103 return headers
104
105 - def set_body_reader(self):
106 chunked = False
107 clength = None
108 for (name, value) in self.headers:
109 if name.upper() == "CONTENT-LENGTH":
110 try:
111 clength = int(value)
112 except ValueError:
113 clength = None
114 elif name.upper() == "TRANSFER-ENCODING":
115 chunked = value.lower() == "chunked"
116 elif name.upper() == "CONTENT-ENCODING":
117 self.encoding = value.lower()
118
119 if chunked:
120 self.body = Body(ChunkedReader(self, self.unreader))
121 elif clength is not None:
122 self.body = Body(LengthReader(self, self.unreader, clength))
123 else:
124 self.body = Body(EOFReader(self, self.unreader))
125
127 for (h, v) in self.headers:
128 if h.lower() == "connection":
129 if v.lower().strip() == "close":
130 return True
131 elif v.lower().strip() == "keep-alive":
132 return False
133 return self.version <= (1, 0)
134
137 self.methre = re.compile("[A-Z0-9$-_.]{3,20}")
138 self.versre = re.compile("HTTP/(\d+).(\d+)")
139
140 self.method = None
141 self.uri = None
142 self.scheme = None
143 self.host = None
144 self.port = 80
145 self.path = None
146 self.query = None
147 self.fragment = None
148
149 super(Request, self).__init__(unreader)
150
152 bits = line.split(None, 2)
153 if len(bits) != 3:
154 raise InvalidRequestLine(line)
155
156
157 if not self.methre.match(bits[0]):
158 raise InvalidRequestMethod(bits[0])
159 self.method = bits[0].upper()
160
161
162 self.uri = bits[1]
163 parts = urlparse.urlparse(bits[1])
164 self.scheme = parts.scheme or None
165 self.host = parts.netloc or None
166 if parts.port is None:
167 self.port = 80
168 else:
169 self.host = self.host.rsplit(":", 1)[0]
170 self.port = parts.port
171 self.path = parts.path or None
172 self.query = parts.query or None
173 self.fragment = parts.fragment or None
174
175
176 match = self.versre.match(bits[2])
177 if match is None:
178 raise InvalidHTTPVersion(bits[2])
179 self.version = (int(match.group(1)), int(match.group(2)))
180
181 - def set_body_reader(self):
182 super(Request, self).set_body_reader()
183 if isinstance(self.body.reader, EOFReader):
184 self.body = Body(LengthReader(self, self.unreader, 0))
185
187
188 - def __init__(self, unreader, decompress=True):
189 self.versre = re.compile("HTTP/(\d+).(\d+)")
190 self.stare = re.compile("(\d{3})\s*(\w*)")
191 self.status = None
192 self.reason = None
193 self.status_int = None
194 self.decompress = decompress
195 super(Response, self).__init__(unreader)
196
198 bits = line.split(None, 1)
199 if len(bits) != 2:
200 raise InvalidRequestLine(line)
201
202
203 matchv = self.versre.match(bits[0])
204 if matchv is None:
205 raise InvalidHTTPVersion(bits[0])
206 self.version = (int(matchv.group(1)), int(matchv.group(2)))
207
208
209 matchs = self.stare.match(bits[1])
210 if matchs is None:
211 raise InvalidHTTPStatus(bits[1])
212
213 self.status = bits[1]
214 self.status_int = int(matchs.group(1))
215 self.reason = matchs.group(2)
216
217 - def set_body_reader(self):
218 super(Response, self).set_body_reader()
219
220 if self.decompress:
221 if self.encoding == "gzip":
222 self.body = GzipBody(self.body.reader)
223 elif self.encoding == "deflate":
224 self.body = DeflateBody(self.body.reader)
225