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]