From f016f0680e4ace6742b03a70cb0382ce86abe371 Mon Sep 17 00:00:00 2001
From: Andrew Svetlov <andrew.svetlov@gmail.com>
Date: Sun, 31 Oct 2021 19:03:06 +0200
Subject: [PATCH] Raise '400: Content-Length can't be present with
 Transfer-Encoding' if both Content-Length and Transfer-Encoding are sent by
 peer (#6182)

---
 CHANGES/6182.bugfix       |  1 +
 aiohttp/http_parser.py    | 12 ++++++++++--
 tests/test_http_parser.py | 15 ++++++++++++++-
 3 files changed, 25 insertions(+), 3 deletions(-)
 create mode 100644 CHANGES/6182.bugfix

diff --git a/CHANGES/6182.bugfix b/CHANGES/6182.bugfix
new file mode 100644
index 0000000000..28daaa328a
--- /dev/null
+++ b/CHANGES/6182.bugfix
@@ -0,0 +1 @@
+Raise ``400: Content-Length can't be present with Transfer-Encoding`` if both ``Content-Length`` and ``Transfer-Encoding`` are sent by peer by both C and Python implementations
diff --git a/aiohttp/http_parser.py b/aiohttp/http_parser.py
index 4a4ae31ae6..e1b86e8e4f 100644
--- a/aiohttp/http_parser.py
+++ b/aiohttp/http_parser.py
@@ -28,6 +28,7 @@
 from .base_protocol import BaseProtocol
 from .helpers import NO_EXTENSIONS, BaseTimerContext
 from .http_exceptions import (
+    BadHttpMessage,
     BadStatusLine,
     ContentEncodingError,
     ContentLengthError,
@@ -489,8 +490,15 @@ def parse_headers(
 
         # chunking
         te = headers.get(hdrs.TRANSFER_ENCODING)
-        if te and "chunked" in te.lower():
-            chunked = True
+        if te is not None:
+            te_lower = te.lower()
+            if "chunked" in te_lower:
+                chunked = True
+
+            if hdrs.CONTENT_LENGTH in headers:
+                raise BadHttpMessage(
+                    "Content-Length can't be present with Transfer-Encoding",
+                )
 
         return (headers, raw_headers, close_conn, encoding, upgrade, chunked)
 
diff --git a/tests/test_http_parser.py b/tests/test_http_parser.py
index 78e9ea6401..d86d238f58 100644
--- a/tests/test_http_parser.py
+++ b/tests/test_http_parser.py
@@ -291,7 +291,20 @@ def test_request_chunked(parser) -> None:
     assert isinstance(payload, streams.StreamReader)
 
 
-def test_conn_upgrade(parser) -> None:
+def test_request_te_chunked_with_content_length(parser: Any) -> None:
+    text = (
+        b"GET /test HTTP/1.1\r\n"
+        b"content-length: 1234\r\n"
+        b"transfer-encoding: chunked\r\n\r\n"
+    )
+    with pytest.raises(
+        http_exceptions.BadHttpMessage,
+        match="Content-Length can't be present with Transfer-Encoding",
+    ):
+        parser.feed_data(text)
+
+
+def test_conn_upgrade(parser: Any) -> None:
     text = (
         b"GET /test HTTP/1.1\r\n"
         b"connection: upgrade\r\n"
