HTTP/1.1 protocol handler for ASGI applications. Handles connection lifecycle, request parsing, and ASGI app invocation. Uses callback-based parsing (H1CProtocol/PythonProtocol) for efficient incremental parsing in data_received().
| 333 | |
| 334 | |
| 335 | class ASGIProtocol(asyncio.Protocol): |
| 336 | """HTTP/1.1 protocol handler for ASGI applications. |
| 337 | |
| 338 | Handles connection lifecycle, request parsing, and ASGI app invocation. |
| 339 | Uses callback-based parsing (H1CProtocol/PythonProtocol) for efficient |
| 340 | incremental parsing in data_received(). |
| 341 | """ |
| 342 | |
| 343 | # Class-level cache for H1CProtocol availability |
| 344 | _h1c_available = None |
| 345 | _h1c_protocol_class = None |
| 346 | _h1c_has_limits = False # True if >= 0.4.1 (has limit parameters) |
| 347 | _h1c_limit_request_line = None # Exception class from gunicorn_h1c >= 0.4.1 |
| 348 | _h1c_limit_request_headers = None # Exception class from gunicorn_h1c >= 0.4.1 |
| 349 | _h1c_invalid_chunk_extension = None # Exception class from gunicorn_h1c >= 0.6.3 |
| 350 | |
| 351 | def __init__(self, worker): |
| 352 | self.worker = worker |
| 353 | self.cfg = worker.cfg |
| 354 | self.log = worker.log |
| 355 | self.app = worker.asgi |
| 356 | |
| 357 | self.transport = None |
| 358 | self.reader = None # Only used for HTTP/2 |
| 359 | self.writer = None |
| 360 | self._task = None |
| 361 | self.req_count = 0 |
| 362 | |
| 363 | # Connection state |
| 364 | self._closed = False |
| 365 | self._body_receiver = None # Set per-request for disconnect signaling |
| 366 | |
| 367 | # Response buffering for write batching |
| 368 | self._response_buffer = None |
| 369 | |
| 370 | # Backpressure control |
| 371 | self._reading_paused = False |
| 372 | self._max_buffer_size = 65536 * 4 # 256KB max buffer (HTTP/2 only) |
| 373 | |
| 374 | # Keep-alive timer |
| 375 | self._keepalive_handle = None |
| 376 | |
| 377 | # Callback parser state |
| 378 | self._callback_parser = None |
| 379 | self._request_ready = None # Event signaling headers complete |
| 380 | self._current_request = None # Request built from parser state |
| 381 | self._is_ssl = False |
| 382 | |
| 383 | # Write flow control |
| 384 | self._flow_control = None |
| 385 | |
| 386 | # WebSocket protocol (set during upgrade, receives data via callbacks) |
| 387 | self._websocket = None |
| 388 | |
| 389 | def connection_made(self, transport): |
| 390 | """Called when a connection is established.""" |
| 391 | self.transport = transport |
| 392 | self.worker.nr_conns += 1 |
no outgoing calls