Skip to content

Support ASGI middleware chains by only yielding http.disconnect when response has been fully received #153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Dec 7, 2022
Merged
11 changes: 7 additions & 4 deletions azure/functions/_http_asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def __init__(self):
self._headers: Union[Headers, Dict] = {}
self._buffer: List[bytes] = []
self._request_body: Optional[bytes] = b""
self._has_received_response: bool = False

@classmethod
async def from_app(cls, app, scope: Dict[str, Any],
Expand Down Expand Up @@ -95,6 +96,7 @@ def _handle_http_response_start(self, message: Dict[str, Any]):

def _handle_http_response_body(self, message: Dict[str, Any]):
self._buffer.append(message["body"])
self._has_received_response = not message.get("more_body", False)
# XXX : Chunked bodies not supported, see
# https://github.com/Azure/azure-functions-host/issues/4926

Expand All @@ -106,14 +108,15 @@ async def _receive(self):
"more_body": False,
}
self._request_body = None
return reply
else:
reply = {
while not self._has_received_response:
await asyncio.sleep(0.1)
return {
"type": "http.disconnect",
}
return reply

async def _send(self, message):
logging.debug(f"Received {message} from ASGI worker.")
if message["type"] == "http.response.start":
self._handle_http_response_start(message)
elif message["type"] == "http.response.body":
Expand Down Expand Up @@ -142,7 +145,7 @@ def __init__(self, app):
main = func.AsgiMiddleware(app).main
"""
if not self._usage_reported:
self._logger.info("Instantiating Azure Functions ASGI middleware.")
self._logger.debug("Starting Azure Functions ASGI middleware.")
self._usage_reported = True

self._app = app
Expand Down
6 changes: 3 additions & 3 deletions tests/test_http_asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ async def __call__(self, scope, receive, send):
assert isinstance(self.received_request['body'], bytes)
assert isinstance(self.received_request['more_body'], bool)

self.next_request = await receive()
assert self.next_request['type'] == 'http.disconnect'

await send(
{
"type": "http.response.start",
Expand All @@ -83,6 +80,9 @@ async def __call__(self, scope, receive, send):
}
)

self.next_request = await receive()
assert self.next_request['type'] == 'http.disconnect'


class TestHttpAsgiMiddleware(unittest.TestCase):
def _generate_func_request(
Expand Down