6 class formwrap(object):
7 def __init__(self, req):
8 if req.ihead.get("Content-Type") == "application/x-www-form-urlencoded":
9 self.cf = cgi.parse(environ = req.env, fp = req.env["wsgi.input"])
11 self.cf = cgi.parse(environ = req.env)
13 def __getitem__(self, key):
14 return self.cf[key][0]
16 def get(self, key, default = ""):
18 return self.cf[key][0]
21 def __contains__(self, key):
22 return key in self.cf and len(self.cf[key]) > 0
29 for key, list in self.cf.items():
35 return list(self.cf.keys())
38 return [val for key, val in self.items()]
40 class badmultipart(Exception):
43 class formpart(object):
44 def __init__(self, form):
53 def fillbuf(self, sz):
55 mboundary = b"\r\n--" + self.form.boundary + b"\r\n"
56 lboundary = b"\r\n--" + self.form.boundary + b"--\r\n"
58 p = self.form.buf.find(mboundary)
60 self.buf += self.form.buf[:p]
61 self.form.buf = self.form.buf[p + len(mboundary):]
64 p = self.form.buf.find(lboundary)
66 self.buf += self.form.buf[:p]
67 self.form.buf = self.form.buf[p + len(lboundary):]
71 self.buf += self.form.buf[:-len(lboundary)]
72 self.form.buf = self.form.buf[-len(lboundary):]
73 if sz >= 0 and len(self.buf) >= sz:
75 while len(self.form.buf) <= len(lboundary):
76 ret = req.env["wsgi.input"].read(8192)
78 raise badmultipart("Missing last multipart boundary")
81 def read(self, limit = -1):
84 ret = self.buf[:limit]
85 self.buf = self.buf[limit:]
91 def readline(self, limit = -1):
94 p = self.buf.find(b'\n', last)
101 self.fillbuf(last + 128)
103 ret = self.buf[:p + 1]
104 self.buf = self.buf[p + 1:]
113 def __exit__(self, *excinfo):
116 def parsehead(self, charset):
118 ln = self.readline(256)
119 if ln[-1] != ord(b'\n'):
120 raise badmultipart("Too long header line in part")
122 return ln.decode(charset).rstrip()
124 raise badmultipart("Form part header is not in assumed charset")
133 if not ln[1:].isspace():
138 raise badmultipart("Malformed multipart header line")
139 self.head[buf[:p].strip().lower()] = buf[p + 1:].lstrip()
141 val, par = proto.pmimehead(self.head.get("content-disposition", ""))
142 if val != "form-data":
143 raise badmultipart("Unexpected Content-Disposition in form part: %r" % val)
144 if not "name" in par:
145 raise badmultipart("Missing name in form part")
146 self.name = par["name"]
147 self.filename = par.get("filename")
148 val, par = proto.pmimehead(self.head.get("content-type", ""))
150 self.charset = par.get("charset")
151 encoding = self.head.get("content-transfer-encoding", "binary")
152 if encoding != "binary":
153 raise badmultipart("Form part uses unexpected transfer encoding: %r" % encoding)
155 class multipart(object):
156 def __init__(self, req, charset):
157 val, par = proto.pmimehead(req.ihead.get("Content-Type", ""))
158 if req.method != "POST" or val != "multipart/form-data":
159 raise badmultipart("Request is not a multipart form")
160 if "boundary" not in par:
161 raise badmultipart("Multipart form lacks boundary")
163 self.boundary = par["boundary"].encode("us-ascii")
165 raise badmultipart("Multipart boundary must be ASCII string")
169 self.headcs = charset
170 self.lastpart = formpart(self)
171 self.lastpart.close()
177 if not self.lastpart.eof:
178 raise RuntimeError("All form parts must be read entirely")
180 raise StopIteration()
181 self.lastpart = formpart(self)
182 self.lastpart.parsehead(self.headcs)
186 return req.item(formwrap)