8 buf.update(urllib.parse.parse_qsl(req.query))
9 if req.ihead.get("Content-Type") == "application/x-www-form-urlencoded":
10 if req.input.limit > 2 ** 20:
11 raise ValueError("x-www-form-urlencoded data is absurdly long")
12 rbody = req.input.read()
13 buf.update(urllib.parse.parse_qsl(rbody.decode("latin1")))
16 class badmultipart(Exception):
19 class formpart(object):
20 def __init__(self, form):
29 def fillbuf(self, sz):
31 mboundary = b"\r\n--" + self.form.boundary + b"\r\n"
32 lboundary = b"\r\n--" + self.form.boundary + b"--\r\n"
34 p = self.form.buf.find(mboundary)
36 self.buf += self.form.buf[:p]
37 self.form.buf = self.form.buf[p + len(mboundary):]
40 p = self.form.buf.find(lboundary)
42 self.buf += self.form.buf[:p]
43 self.form.buf = self.form.buf[p + len(lboundary):]
47 self.buf += self.form.buf[:-len(lboundary)]
48 self.form.buf = self.form.buf[-len(lboundary):]
49 if sz >= 0 and len(self.buf) >= sz:
51 while len(self.form.buf) <= len(lboundary):
52 ret = req.input.read(8192)
54 raise badmultipart("Missing last multipart boundary")
57 def read(self, limit=-1):
60 ret = self.buf[:limit]
61 self.buf = self.buf[limit:]
67 def readline(self, limit=-1):
70 p = self.buf.find(b'\n', last)
77 self.fillbuf(last + 128)
79 ret = self.buf[:p + 1]
80 self.buf = self.buf[p + 1:]
89 def __exit__(self, *excinfo):
93 def parsehead(self, charset):
95 ln = self.readline(256)
96 if ln[-1] != ord(b'\n'):
97 raise badmultipart("Too long header line in part")
99 return ln.decode(charset).rstrip()
101 raise badmultipart("Form part header is not in assumed charset")
110 if not ln[1:].isspace():
115 raise badmultipart("Malformed multipart header line")
116 self.head[buf[:p].strip().lower()] = buf[p + 1:].lstrip()
118 val, par = proto.pmimehead(self.head.get("content-disposition", ""))
119 if val != "form-data":
120 raise badmultipart("Unexpected Content-Disposition in form part: %r" % val)
121 if not "name" in par:
122 raise badmultipart("Missing name in form part")
123 self.name = par["name"]
124 self.filename = par.get("filename")
125 val, par = proto.pmimehead(self.head.get("content-type", ""))
127 self.charset = par.get("charset")
128 encoding = self.head.get("content-transfer-encoding", "binary")
129 if encoding != "binary":
130 raise badmultipart("Form part uses unexpected transfer encoding: %r" % encoding)
132 class multipart(object):
133 def __init__(self, req, charset):
134 val, par = proto.pmimehead(req.ihead.get("Content-Type", ""))
135 if req.method != "POST" or val != "multipart/form-data":
136 raise badmultipart("Request is not a multipart form")
137 if "boundary" not in par:
138 raise badmultipart("Multipart form lacks boundary")
140 self.boundary = par["boundary"].encode("us-ascii")
142 raise badmultipart("Multipart boundary must be ASCII string")
146 self.headcs = charset
147 self.lastpart = formpart(self)
148 self.lastpart.close()
154 if not self.lastpart.eof:
155 raise RuntimeError("All form parts must be read entirely")
157 raise StopIteration()
158 self.lastpart = formpart(self)
159 self.lastpart.parsehead(self.headcs)
163 return req.item(formparse)