dabla commented on code in PR #72398:
URL: https://github.com/apache/airflow/pull/72398#discussion_r4307214566


##########
providers/http/src/airflow/providers/http/hooks/http.py:
##########
@@ -687,6 +711,35 @@ async def request_func() -> ClientResponse:
 
         raise NotImplementedError  # should not reach this, but makes mypy 
happy
 
+    async def _send(
+        self,
+        url: str,
+        *,
+        data: dict[str, Any] | str | None,
+        json: dict[str, Any] | str | None,
+        headers: dict[str, Any],
+        extra_options: dict[str, Any],
+    ) -> ClientResponse:
+        extra_options = dict(extra_options)
+        connection_header_names = set(self.config.connection_headers)

Review Comment:
   **[warning]** A header the caller passes is dropped on a cross-origin hop 
when the Extra has a header of the same name. The sync hook keeps it.
   
   `config.connection_headers` holds every Extra key. `run()` then lays the 
caller's `headers=` over the Extra values in `merged_headers`, but the names 
stay in the set, so the middleware pops the caller's value as well. To check, I 
ran this head against two local aiohttp servers on different ports. The Extra 
was `{"X-API-Key": "s", "Accept": "application/json"}` and the call was 
`run(endpoint=..., headers={"Accept": "text/csv", "X-Caller": "c"})`. The 
redirect target got `X-Caller` but no `Accept`.
   
   #72165 handles this the other way on purpose. `get_conn` removes caller and 
`default_headers` names from the tracked set, and 
`test_caller_header_overriding_connection_header_is_kept` covers it, because 
the caller controls the request either way. If the two PRs land together as 
planned, the same `run(headers=...)` call would behave differently on 
`HttpHook` and `HttpAsyncHook`.
   
   Suggestion: compute the names in `run()`, where the caller's headers are 
still separate, and pass them down instead of reading 
`self.config.connection_headers` in `_send`:
   
   ```python
   caller_names = {str(name).lower() for name in headers or {}}
   connection_header_names = {
       name for name in self.config.connection_headers if name.lower() not in 
caller_names
   }
   ```
   
   A case like #72165's parametrized test (`Accept` / `accept` / `ACCEPT`) 
would keep the two hooks aligned.



##########
providers/http/docs/changelog.rst:
##########
@@ -27,6 +27,14 @@
 Changelog
 ---------
 
+.. warning::

Review Comment:
   **[nit]** The note reads as if it covers every HTTP hook, but it describes 
only `HttpAsyncHook`.
   
   "Extra headers from the HTTP Connection are sent on the first request and on 
redirects that stay on the same origin" is true for `HttpHook` only once #72165 
is merged. The last sentence ("follow aiohttp's origin rules") then applies to 
the async hook alone. Same for the paragraph in `connections/http.rst`. #72165 
adds no note of its own, which I raised on that PR. One wording that names both 
hooks would hold whichever merges first, e.g. "`HttpHook` and `HttpAsyncHook` 
do not forward Extra headers when a redirect leaves the origin of the first 
request …".
   
   It would also help to give the two ways out for anyone who relied on the old 
behaviour (raised on #70000 for the same change): point the connection at the 
final host, or set `allow_redirects=False` and make the second request yourself.



-- 
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