diff --git a/gunicorn/http/message.py b/gunicorn/http/message.py index 67fffd9e..4e1c2fd5 100644 --- a/gunicorn/http/message.py +++ b/gunicorn/http/message.py @@ -98,12 +98,16 @@ class Message(object): raise InvalidHeader(curr) name, value = curr.split(":", 1) if self.cfg.strip_header_spaces: - name = name.rstrip(" \t").upper() - else: - name = name.upper() + name = name.rstrip(" \t") if not TOKEN_RE.fullmatch(name): raise InvalidHeaderName(name) + # this is still a dangerous place to do this + # but it is more correct than doing it before the pattern match: + # after we entered Unicode wonderland, 8bits could case-shift into ASCII: + # b"\xDF".decode("latin-1").upper().encode("ascii") == b"SS" + name = name.upper() + value = [value.lstrip(" \t")] # Consume value continuation lines diff --git a/tests/requests/invalid/nonascii_03.http b/tests/requests/invalid/nonascii_03.http new file mode 100644 index 00000000..eda5d010 --- /dev/null +++ b/tests/requests/invalid/nonascii_03.http @@ -0,0 +1,5 @@ +GET /germans.. HTTP/1.1\r\n +Content-Lengthß: 3\r\n +Content-Length: 3\r\n +\r\n +ÄÄÄ diff --git a/tests/requests/invalid/nonascii_03.py b/tests/requests/invalid/nonascii_03.py new file mode 100644 index 00000000..d336fbc8 --- /dev/null +++ b/tests/requests/invalid/nonascii_03.py @@ -0,0 +1,5 @@ +from gunicorn.config import Config +from gunicorn.http.errors import InvalidHeaderName + +cfg = Config() +request = InvalidHeaderName