1import re
2from cgi import parse_header
3
4from .headers import HeaderElement
5from .parsers import MultipartParser
6from .parsers import QueryStringParser
7
8
9def process_multipart(request, params):
10    headers = request.headers
11
12    ctype = headers.elements("Content-Type")
13    if ctype:
14        ctype = ctype[0]
15    else:
16        ctype = HeaderElement.from_str("application/x-www-form-urlencoded")
17
18    ib = ""
19    if "boundary" in ctype.params:
20        # http://tools.ietf.org/html/rfc2046#section-5.1.1
21        # "The grammar for parameters on the Content-type field is such that it
22        # is often necessary to enclose the boundary parameter values in quotes
23        # on the Content-type line"
24        ib = ctype.params["boundary"].strip("\"")
25
26    if not re.match("^[ -~]{0,200}[!-~]$", ib):
27        raise ValueError("Invalid boundary in multipart form: %r" % (ib,))
28
29    parser = MultipartParser(request.body, ib)
30    for part in parser:
31        if part.filename or not part.is_buffered():
32            params[part.name] = part
33        else:
34            params[part.name] = part.value
35
36
37def process_urlencoded(request, params, encoding="utf-8"):
38    params.update(QueryStringParser(request.qs).result)
39    body = request.body.getvalue().decode(encoding)
40    params.update(QueryStringParser(body).result)
41
42
43def process(request, params):
44    ctype = request.headers.get("Content-Type")
45    if not ctype:
46        return
47
48    mtype, mencoding = ctype.split("/", 1) if "/" in ctype else (ctype, None)
49    mencoding, extra = parse_header(mencoding)
50
51    charset = extra.get("charset", "utf-8")
52
53    if mtype == "multipart":
54        process_multipart(request, params)
55    elif mtype == "application" and mencoding == "x-www-form-urlencoded":
56        process_urlencoded(request, params, encoding=charset)
57