falconry / falcon

The no-magic web data plane API and microservices framework for Python developers, with a focus on reliability, correctness, and performance at scale.
https://falcon.readthedocs.io/en/stable/
Apache License 2.0
9.51k stars 937 forks source link

Replace usage of `cgi.parse_header()` (slated for removal in 3.13) #2066

Closed vytas7 closed 6 months ago

vytas7 commented 2 years ago

PEP 594 specifies removal of "dead batteries" in CPython 3.13, with deprecation announced in 3.11.

Apparently, cgi is also on the chopping block, so we'll have to replace cgi.parse_header(). At first glance, the suggested replacement (instantiating an email.message.Message) looks clunky and likely to perform worse. Maybe we can reimplement it in Cython instead?

mikael-epigram commented 1 year ago

As an alternative why not just use the cgi sourcecode. It seems quite standalone?

https://github.com/python/cpython/blob/3.11/Lib/cgi.py#L238

def _parseparam(s):
    while s[:1] == ';':
        s = s[1:]
        end = s.find(';')
        while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2:
            end = s.find(';', end + 1)
        if end < 0:
            end = len(s)
        f = s[:end]
        yield f.strip()
        s = s[end:]

def parse_header(line):
    """Parse a Content-type like header.
    Return the main content-type and a dictionary of options.
    """
    parts = _parseparam(';' + line)
    key = parts.__next__()
    pdict = {}
    for p in parts:
        i = p.find('=')
        if i >= 0:
            name = p[:i].strip().lower()
            value = p[i+1:].strip()
            if len(value) >= 2 and value[0] == value[-1] == '"':
                value = value[1:-1]
                value = value.replace('\\\\', '\\').replace('\\"', '"')
            pdict[name] = value
    return key, pdict
vytas7 commented 1 year ago

Hi @mikael-epigram, and thanks for reaching out! At a glance this doesn't look very performant, we'll try to write a faster version in both Python (for PyPy) and Cython. But yes, in a pinch, just vendoring this snippet would do.

mikael-epigram commented 1 year ago

I agree that it does not seem that performant, but that is what you are already using on CPython