8 buf.update(urllib.parse.parse_qsl(req.query, keep_blank_values=True))
9 ctype, ctpars = proto.pmimehead(req.ihead.get("Content-Type", ""))
10 if ctype == "application/x-www-form-urlencoded":
12 rbody = req.input.read(2 ** 20)
13 except IOError as exc:
15 if len(rbody) >= 2 ** 20:
16 return ValueError("x-www-form-urlencoded data is absurdly long")
17 buf.update(urllib.parse.parse_qsl(rbody.decode("latin1"), encoding=ctpars.get("charset", "utf-8"), keep_blank_values=True))
20 class badmultipart(IOError):
23 class formpart(object):
24 def __init__(self, form):
33 def fillbuf(self, sz):
35 mboundary = b"\r\n--" + self.form.boundary + b"\r\n"
36 lboundary = b"\r\n--" + self.form.boundary + b"--\r\n"
38 p = self.form.buf.find(mboundary)
40 self.buf += self.form.buf[:p]
41 self.form.buf = self.form.buf[p + len(mboundary):]
44 p = self.form.buf.find(lboundary)
46 self.buf += self.form.buf[:p]
47 self.form.buf = self.form.buf[p + len(lboundary):]
51 self.buf += self.form.buf[:-len(lboundary)]
52 self.form.buf = self.form.buf[-len(lboundary):]
53 if sz >= 0 and len(self.buf) >= sz:
55 while len(self.form.buf) <= len(lboundary):
56 ret = req.input.read(8192)
58 raise badmultipart("Missing last multipart boundary")
61 def read(self, limit=-1):
64 ret = self.buf[:limit]
65 self.buf = self.buf[limit:]
71 def readline(self, limit=-1):
74 p = self.buf.find(b'\n', last)
81 self.fillbuf(last + 128)
83 ret = self.buf[:p + 1]
84 self.buf = self.buf[p + 1:]
89 if self.read(8192) == b"":
95 def __exit__(self, *excinfo):
99 def parsehead(self, charset):
101 ln = self.readline(256)
102 if ln[-1] != ord(b'\n'):
103 raise badmultipart("Too long header line in part")
105 return ln.decode(charset).rstrip()
107 raise badmultipart("Form part header is not in assumed charset")
116 if not ln[1:].isspace():
121 raise badmultipart("Malformed multipart header line")
122 self.head[buf[:p].strip().lower()] = buf[p + 1:].lstrip()
124 val, par = proto.pmimehead(self.head.get("content-disposition", ""))
125 if val != "form-data":
126 raise badmultipart("Unexpected Content-Disposition in form part: %r" % val)
127 if not "name" in par:
128 raise badmultipart("Missing name in form part")
129 self.name = par["name"]
130 self.filename = par.get("filename")
131 val, par = proto.pmimehead(self.head.get("content-type", ""))
133 self.charset = par.get("charset")
134 encoding = self.head.get("content-transfer-encoding", "binary")
135 if encoding != "binary":
136 raise badmultipart("Form part uses unexpected transfer encoding: %r" % encoding)
138 class multipart(object):
139 def __init__(self, req, charset):
140 val, par = proto.pmimehead(req.ihead.get("Content-Type", ""))
141 if req.method != "POST" or val != "multipart/form-data":
142 raise badmultipart("Request is not a multipart form")
143 if "boundary" not in par:
144 raise badmultipart("Multipart form lacks boundary")
146 self.boundary = par["boundary"].encode("us-ascii")
148 raise badmultipart("Multipart boundary must be ASCII string")
152 self.headcs = charset
153 self.lastpart = formpart(self)
154 self.lastpart.close()
160 if not self.lastpart.eof:
161 raise RuntimeError("All form parts must be read entirely")
163 raise StopIteration()
164 self.lastpart = formpart(self)
165 self.lastpart.parsehead(self.headcs)
168 def formdata(req, onerror=Exception):
169 data = req.item(formparse)
170 if isinstance(data, Exception):
171 if onerror is Exception: