fix(http): don't let a non-iterable header buffer crash end_headers
advertise_connection_close() guarded its two attribute reads but not the dedup scan over _headers_buffer. A stub whose buffer is truthy and non-iterable (a bare Mock) raised TypeError from inside end_headers(), which _handle_write's generic except would swallow into a spurious 500 -- the same failure class as the missing close_connection guard.
This commit is contained in:
1 parent
a93e8ba890
commit
304815228a
2 files changed
+27
-2
No files matched your search
+7
-2
@@ -236,11 +236,16 @@ def advertise_connection_close(handler) -> None:
|
||||
|
||||
Both attribute reads are defensive: partially-built handler stubs in the
|
||||
test suite carry neither ``close_connection`` nor ``_headers_buffer``, and
|
||||
header emission must not depend on their presence.
|
||||
header emission must not depend on their presence. The buffer is also
|
||||
type-checked before it is scanned -- a stub whose ``_headers_buffer`` is a
|
||||
truthy non-iterable (a bare ``Mock``) would otherwise raise ``TypeError``
|
||||
from inside ``end_headers()``, which ``_handle_write`` would swallow into a
|
||||
spurious 500.
|
||||
"""
|
||||
if not getattr(handler, 'close_connection', False):
|
||||
return
|
||||
for raw in getattr(handler, '_headers_buffer', None) or ():
|
||||
buffered = getattr(handler, '_headers_buffer', None)
|
||||
for raw in buffered if isinstance(buffered, (list, tuple)) else ():
|
||||
if raw[:11].lower() == b'connection:':
|
||||
return
|
||||
handler.send_header('Connection', 'close')
|
||||
|
||||
@@ -228,6 +228,26 @@ def test_end_headers_on_handler_stub_without_close_connection(monkeypatch):
|
||||
assert "Connection" not in dict(sent), "nothing was armed, so nothing to advertise"
|
||||
|
||||
|
||||
def test_advertise_close_tolerates_a_non_iterable_header_buffer():
|
||||
"""The dedup scan must be as defensive as the two attribute reads.
|
||||
|
||||
A bare ``Mock`` answers every attribute, so ``_headers_buffer`` comes back
|
||||
truthy but non-iterable. Iterating it unguarded raised
|
||||
``TypeError: 'Mock' object is not iterable`` from inside ``end_headers()``,
|
||||
which ``_handle_write``'s generic ``except`` turns into a spurious 500 —
|
||||
the same crash-inside-end_headers class as the missing
|
||||
``close_connection`` guard above.
|
||||
"""
|
||||
from unittest.mock import Mock
|
||||
|
||||
from api.helpers import advertise_connection_close
|
||||
|
||||
handler = Mock()
|
||||
advertise_connection_close(handler) # must not raise
|
||||
|
||||
handler.send_header.assert_called_once_with("Connection", "close")
|
||||
|
||||
|
||||
def test_check_auth_or_close_on_handler_stub_without_close_connection(monkeypatch):
|
||||
"""check_auth_or_close must not invent close_connection on a stub.
|
||||
|
||||
|
||||
Reference in new issue
Block a user