File CVE-2024-6827.patch of Package python-gunicorn.38005

Index: gunicorn-19.7.1/gunicorn/config.py
===================================================================
--- gunicorn-19.7.1.orig/gunicorn/config.py
+++ gunicorn-19.7.1/gunicorn/config.py
@@ -1964,21 +1964,3 @@ class HeaderMap(Setting):
 
         .. versionadded:: 22.0.0
         """
-
-
-class TolerateDangerousFraming(Setting):
-    name = "tolerate_dangerous_framing"
-    section = "Server Mechanics"
-    cli = ["--tolerate-dangerous-framing"]
-    validator = validate_bool
-    action = "store_true"
-    default = False
-    desc = """\
-        Process requests with both Transfer-Encoding and Content-Length
-
-        This is known to induce vulnerabilities, but not strictly forbidden by RFC9112.
-
-        Use with care and only if necessary. May be removed in a future version.
-
-        .. versionadded:: 22.0.0
-        """
Index: gunicorn-19.7.1/gunicorn/http/message.py
===================================================================
--- gunicorn-19.7.1.orig/gunicorn/http/message.py
+++ gunicorn-19.7.1/gunicorn/http/message.py
@@ -136,31 +136,27 @@ class Message(object):
             if name == "CONTENT-LENGTH":
                 content_length = value
             elif name == "TRANSFER-ENCODING":
-                if value.lower() == "chunked":
-                    # DANGER: transer codings stack, and stacked chunking is never intended
-                    if chunked:
-                        raise InvalidHeader("TRANSFER-ENCODING", req=self)
-                    chunked = True
-                elif value.lower() == "identity":
-                    # does not do much, could still plausibly desync from what the proxy does
-                    # safe option: nuke it, its never needed
-                    if chunked:
-                        raise InvalidHeader("TRANSFER-ENCODING", req=self)
-                elif value.lower() == "":
-                    # lacking security review on this case
-                    # offer the option to restore previous behaviour, but refuse by default, for now
-                    self.force_close()
-                    if not self.cfg.tolerate_dangerous_framing:
+                # T-E can be a list
+                # https://datatracker.ietf.org/doc/html/rfc9112#name-transfer-encoding
+                vals = [v.strip() for v in value.split(',')]
+                for val in vals:
+                    if val.lower() == "chunked":
+                        # DANGER: transfer codings stack, and stacked chunking is never intended
+                        if chunked:
+                            raise InvalidHeader("TRANSFER-ENCODING", req=self)
+                        chunked = True
+                    elif val.lower() == "identity":
+                        # does not do much, could still plausibly desync from what the proxy does
+                        # safe option: nuke it, its never needed
+                        if chunked:
+                            raise InvalidHeader("TRANSFER-ENCODING", req=self)
+                    elif val.lower() in ('compress', 'deflate', 'gzip'):
+                        # chunked should be the last one
+                        if chunked:
+                            raise InvalidHeader("TRANSFER-ENCODING", req=self)
+                        self.force_close()
+                    else:
                         raise UnsupportedTransferCoding(value)
-                # DANGER: do not change lightly; ref: request smuggling
-                # T-E is a list and we *could* support correctly parsing its elements
-                #  .. but that is only safe after getting all the edge cases right
-                #  .. for which no real-world need exists, so best to NOT open that can of worms
-                else:
-                    self.force_close()
-                    # even if parser is extended, retain this branch:
-                    #  the "chunked not last" case remains to be rejected!
-                    raise UnsupportedTransferCoding(value)
             elif name == "SEC-WEBSOCKET-KEY1":
                 content_length = 8
 
@@ -170,16 +166,11 @@ class Message(object):
             #  b) chunked HTTP/1.0 (always faulty)
             if self.version < (1, 1):
                 # framing wonky, see RFC 9112 Section 6.1
-                self.force_close()
-                if not self.cfg.tolerate_dangerous_framing:
-                    raise InvalidHeader("TRANSFER-ENCODING", req=self)
+                raise InvalidHeader("TRANSFER-ENCODING", req=self)
             if content_length is not None:
                 # we cannot be certain the message framing we understood matches proxy intent
                 #  -> whatever happens next, remaining input must not be trusted
-                self.force_close()
-                # either processing or rejecting is permitted in RFC 9112 Section 6.1
-                if not self.cfg.tolerate_dangerous_framing:
-                    raise InvalidHeader("CONTENT-LENGTH", req=self)
+                raise InvalidHeader("CONTENT-LENGTH", req=self)
             self.body = Body(ChunkedReader(self, self.unreader))
         elif content_length is not None:
             try:
Index: gunicorn-19.7.1/tests/requests/invalid/chunked_03.py
===================================================================
--- gunicorn-19.7.1.orig/tests/requests/invalid/chunked_03.py
+++ gunicorn-19.7.1/tests/requests/invalid/chunked_03.py
@@ -1,2 +1,2 @@
-from gunicorn.http.errors import UnsupportedTransferCoding
-request = UnsupportedTransferCoding
+from gunicorn.http.errors import InvalidHeader 
+request = InvalidHeader 
Index: gunicorn-19.7.1/tests/requests/invalid/chunked_06.py
===================================================================
--- gunicorn-19.7.1.orig/tests/requests/invalid/chunked_06.py
+++ gunicorn-19.7.1/tests/requests/invalid/chunked_06.py
@@ -1,2 +1,2 @@
-from gunicorn.http.errors import UnsupportedTransferCoding
-request = UnsupportedTransferCoding
+from gunicorn.http.errors import InvalidHeader 
+request = InvalidHeader 
Index: gunicorn-19.7.1/tests/requests/valid/025.http
===================================================================
--- gunicorn-19.7.1.orig/tests/requests/valid/025.http
+++ gunicorn-19.7.1/tests/requests/valid/025.http
@@ -1,24 +1,10 @@
-POST /chunked_cont_h_at_first HTTP/1.1\r\n
+POST /chunked HTTP/1.1\r\n
+Transfer-Encoding: gzip\r\n
 Transfer-Encoding: chunked\r\n
 \r\n
-5; some; parameters=stuff\r\n
+5\r\n
 hello\r\n
-6 \t;\tblahblah; blah\r\n
+6\r\n
  world\r\n
 0\r\n
 \r\n
-PUT /chunked_cont_h_at_last HTTP/1.1\r\n
-Transfer-Encoding: chunked\r\n
-Content-Length: -1\r\n
-\r\n
-5; some; parameters=stuff\r\n
-hello\r\n
-6; blahblah; blah\r\n
- world\r\n
-0\r\n
-\r\n
-PUT /ignored_after_dangerous_framing HTTP/1.1\r\n
-Content-Length: 3\r\n
-\r\n
-foo\r\n
-\r\n
Index: gunicorn-19.7.1/tests/requests/valid/025.py
===================================================================
--- gunicorn-19.7.1.orig/tests/requests/valid/025.py
+++ gunicorn-19.7.1/tests/requests/valid/025.py
@@ -1,27 +1,10 @@
-from gunicorn.config import Config
-
-cfg = Config()
-cfg.set("tolerate_dangerous_framing", True)
-
-req1 = {
+request = {
     "method": "POST",
-    "uri": uri("/chunked_cont_h_at_first"),
+    "uri": uri("/chunked"),
     "version": (1, 1),
     "headers": [
-        ("TRANSFER-ENCODING", "chunked")
+        ('TRANSFER-ENCODING', 'gzip'),
+        ('TRANSFER-ENCODING', 'chunked')
     ],
     "body": b"hello world"
 }
-
-req2 = {
-    "method": "PUT",
-    "uri": uri("/chunked_cont_h_at_last"),
-    "version": (1, 1),
-    "headers": [
-        ("TRANSFER-ENCODING", "chunked"),
-        ("CONTENT-LENGTH", "-1"),
-    ],
-    "body": b"hello world"
-}
-
-request = [req1, req2]
Index: gunicorn-19.7.1/tests/requests/valid/025_line.http
===================================================================
--- /dev/null
+++ gunicorn-19.7.1/tests/requests/valid/025_line.http
@@ -0,0 +1,9 @@
+POST /chunked HTTP/1.1\r\n
+Transfer-Encoding: gzip,chunked\r\n
+\r\n
+5\r\n
+hello\r\n
+6\r\n
+ world\r\n
+0\r\n
+\r\n
Index: gunicorn-19.7.1/tests/requests/valid/025_line.py
===================================================================
--- /dev/null
+++ gunicorn-19.7.1/tests/requests/valid/025_line.py
@@ -0,0 +1,10 @@
+request = {
+    "method": "POST",
+    "uri": uri("/chunked"),
+    "version": (1, 1),
+    "headers": [
+        ('TRANSFER-ENCODING', 'gzip,chunked')
+
+    ],
+    "body": b"hello world"
+}
Index: gunicorn-19.7.1/tests/requests/valid/025compat.http
===================================================================
--- gunicorn-19.7.1.orig/tests/requests/valid/025compat.http
+++ /dev/null
@@ -1,18 +0,0 @@
-POST /chunked_cont_h_at_first HTTP/1.1\r\n
-Transfer-Encoding: chunked\r\n
-\r\n
-5; some; parameters=stuff\r\n
-hello\r\n
-6; blahblah; blah\r\n
- world\r\n
-0\r\n
-\r\n
-PUT /chunked_cont_h_at_last HTTP/1.1\r\n
-Transfer-Encoding: chunked\r\n
-Content-Length: -1\r\n
-\r\n
-5; some; parameters=stuff\r\n
-hello\r\n
-6; blahblah; blah\r\n
- world\r\n
-0\r\n
Index: gunicorn-19.7.1/tests/requests/valid/025compat.py
===================================================================
--- gunicorn-19.7.1.orig/tests/requests/valid/025compat.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from gunicorn.config import Config
-
-cfg = Config()
-cfg.set("tolerate_dangerous_framing", True)
-
-req1 = {
-    "method": "POST",
-    "uri": uri("/chunked_cont_h_at_first"),
-    "version": (1, 1),
-    "headers": [
-        ("TRANSFER-ENCODING", "chunked")
-    ],
-    "body": b"hello world"
-}
-
-req2 = {
-    "method": "PUT",
-    "uri": uri("/chunked_cont_h_at_last"),
-    "version": (1, 1),
-    "headers": [
-        ("TRANSFER-ENCODING", "chunked"),
-        ("CONTENT-LENGTH", "-1"),
-    ],
-    "body": b"hello world"
-}
-
-request = [req1, req2]
openSUSE Build Service is sponsored by