Copilot commented on code in PR #64688:
URL: https://github.com/apache/airflow/pull/64688#discussion_r3066476789


##########
airflow-core/src/airflow/api_fastapi/core_api/app.py:
##########
@@ -167,7 +167,9 @@ def init_error_handlers(app: FastAPI) -> None:
 def init_middlewares(app: FastAPI) -> None:
     from airflow.api_fastapi.auth.middlewares.refresh_token import 
JWTRefreshMiddleware
     from airflow.api_fastapi.common.http_access_log import 
HttpAccessLogMiddleware
+    from airflow.api_fastapi.common.remove_duplicate_date_header import 
RemoveDuplicateDateHeaderMiddleware
 
+    app.add_middleware(RemoveDuplicateDateHeaderMiddleware)
     app.add_middleware(JWTRefreshMiddleware)

Review Comment:
   The PR description states the fix is achieved by disabling uvicorn’s Date 
header via `date_header=False`, but the diff also adds and enables a new 
`RemoveDuplicateDateHeaderMiddleware`. Either update the PR description to 
include this additional behavioral change (and why it’s still needed with 
`date_header=False`), or remove the middleware if the uvicorn config change 
fully resolves the issue.



##########
airflow-core/src/airflow/api_fastapi/core_api/app.py:
##########
@@ -167,7 +167,9 @@ def init_error_handlers(app: FastAPI) -> None:
 def init_middlewares(app: FastAPI) -> None:
     from airflow.api_fastapi.auth.middlewares.refresh_token import 
JWTRefreshMiddleware
     from airflow.api_fastapi.common.http_access_log import 
HttpAccessLogMiddleware
+    from airflow.api_fastapi.common.remove_duplicate_date_header import 
RemoveDuplicateDateHeaderMiddleware
 
+    app.add_middleware(RemoveDuplicateDateHeaderMiddleware)
     app.add_middleware(JWTRefreshMiddleware)

Review Comment:
   In Starlette/FastAPI, middleware execution order is affected by the order of 
`add_middleware`; as written, `RemoveDuplicateDateHeaderMiddleware` is likely 
not the outermost middleware and may not see the final headers after other 
middlewares mutate them. To ensure it deduplicates the final outgoing headers, 
register it last (so it wraps the whole stack).



##########
airflow-core/src/airflow/api_fastapi/common/remove_duplicate_date_header.py:
##########
@@ -0,0 +1,73 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from typing import Awaitable, Callable
+
+from starlette.datastructures import MutableHeaders
+from starlette.types import ASGIApp, Message, Receive, Scope, Send
+
+
+class RemoveDuplicateDateHeaderMiddleware:
+    """
+    Remove duplicate Date headers that can occur when Flask WSGI middleware is 
mounted.
+
+    When Flask WSGI plugins are loaded, responses can contain duplicate Date 
headers -
+    one from uvicorn and one from Flask. This middleware keeps only the first 
Date header
+    and removes any subsequent duplicates.
+
+    This works at the ASGI level, intercepting http.response.start messages 
before headers
+    are sent to the client.
+    """
+
+    def __init__(self, app: ASGIApp) -> None:
+        self.app = app
+
+    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> 
None:
+        if scope["type"] != "http":
+            await self.app(scope, receive, send)
+            return
+
+        async def send_with_deduplicated_headers(message: Message) -> None:
+            if message["type"] == "http.response.start":

Review Comment:
   This new middleware introduces non-trivial response mutation logic but no 
accompanying unit tests are shown. Add tests that (1) verify multiple `Date` 
headers are reduced to exactly one, and (2) validate the chosen precedence 
(first vs last) matches the intended behavior. This will prevent regressions, 
especially since middleware ordering affects outcomes.



##########
airflow-core/src/airflow/api_fastapi/common/remove_duplicate_date_header.py:
##########
@@ -0,0 +1,73 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from typing import Awaitable, Callable
+
+from starlette.datastructures import MutableHeaders
+from starlette.types import ASGIApp, Message, Receive, Scope, Send
+
+
+class RemoveDuplicateDateHeaderMiddleware:
+    """
+    Remove duplicate Date headers that can occur when Flask WSGI middleware is 
mounted.
+
+    When Flask WSGI plugins are loaded, responses can contain duplicate Date 
headers -
+    one from uvicorn and one from Flask. This middleware keeps only the first 
Date header
+    and removes any subsequent duplicates.
+
+    This works at the ASGI level, intercepting http.response.start messages 
before headers
+    are sent to the client.
+    """
+
+    def __init__(self, app: ASGIApp) -> None:
+        self.app = app
+
+    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> 
None:

Review Comment:
   This new middleware introduces non-trivial response mutation logic but no 
accompanying unit tests are shown. Add tests that (1) verify multiple `Date` 
headers are reduced to exactly one, and (2) validate the chosen precedence 
(first vs last) matches the intended behavior. This will prevent regressions, 
especially since middleware ordering affects outcomes.



##########
airflow-core/src/airflow/api_fastapi/common/remove_duplicate_date_header.py:
##########
@@ -0,0 +1,73 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from typing import Awaitable, Callable
+
+from starlette.datastructures import MutableHeaders
+from starlette.types import ASGIApp, Message, Receive, Scope, Send
+
+
+class RemoveDuplicateDateHeaderMiddleware:
+    """
+    Remove duplicate Date headers that can occur when Flask WSGI middleware is 
mounted.
+
+    When Flask WSGI plugins are loaded, responses can contain duplicate Date 
headers -
+    one from uvicorn and one from Flask. This middleware keeps only the first 
Date header
+    and removes any subsequent duplicates.
+
+    This works at the ASGI level, intercepting http.response.start messages 
before headers
+    are sent to the client.

Review Comment:
   The docstring claims this removes duplicates “one from uvicorn and one from 
Flask,” but uvicorn may inject its `Date` header at the server/protocol layer 
(outside the ASGI app’s `http.response.start` message). If that’s the case, 
this middleware won’t observe or remove the uvicorn-added header. Either (a) 
remove this middleware as redundant given `date_header=False`, or (b) re-scope 
the docstring to only claim deduplication for duplicates produced within the 
ASGI app/middleware stack.
   ```suggestion
       Remove duplicate Date headers present in ASGI response headers.
   
       When Flask WSGI plugins or other app-level middleware are mounted, 
responses can
       contain multiple Date headers in the ASGI ``http.response.start`` 
message. This
       middleware keeps only the first Date header and removes any subsequent 
duplicates
       from that message.
   
       This operates only at the ASGI level, intercepting 
``http.response.start`` messages
       before headers are sent to the client.
   ```



##########
airflow-core/src/airflow/api_fastapi/common/remove_duplicate_date_header.py:
##########
@@ -0,0 +1,73 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from typing import Awaitable, Callable
+
+from starlette.datastructures import MutableHeaders
+from starlette.types import ASGIApp, Message, Receive, Scope, Send
+
+
+class RemoveDuplicateDateHeaderMiddleware:
+    """
+    Remove duplicate Date headers that can occur when Flask WSGI middleware is 
mounted.
+
+    When Flask WSGI plugins are loaded, responses can contain duplicate Date 
headers -
+    one from uvicorn and one from Flask. This middleware keeps only the first 
Date header
+    and removes any subsequent duplicates.
+
+    This works at the ASGI level, intercepting http.response.start messages 
before headers
+    are sent to the client.
+    """
+
+    def __init__(self, app: ASGIApp) -> None:
+        self.app = app
+
+    async def __call__(self, scope: Scope, receive: Receive, send: Send) -> 
None:
+        if scope["type"] != "http":
+            await self.app(scope, receive, send)
+            return
+
+        async def send_with_deduplicated_headers(message: Message) -> None:
+            if message["type"] == "http.response.start":
+                # Extract headers and look for duplicates
+                headers = MutableHeaders(raw=message["headers"])
+
+                # Find all Date headers (case-insensitive)
+                date_headers = []
+                for header_name, header_value in message["headers"]:
+                    if header_name.lower() == b"date":
+                        date_headers.append(header_value)
+
+                # If there are multiple Date headers, keep only the first
+                if len(date_headers) > 1:
+                    # Remove all Date headers
+                    del headers["date"]
+
+                    # Re-add the first one
+                    headers["date"] = (
+                        date_headers[0].decode("utf-8")
+                        if isinstance(date_headers[0], bytes)
+                        else date_headers[0]
+                    )

Review Comment:
   The middleware keeps the *first* `Date` header, but the PR’s stated intent 
is to “let Flask handle it exclusively.” If duplicates arise from two different 
layers, keeping the first can preserve the wrong source depending on header 
insertion order. Prefer keeping the last `Date` header (or explicitly keeping 
the WSGI/Flask-provided value if deterministically identifiable), and align the 
docstring/comment accordingly.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to