(conn: Connection, length: int, deadline: Optional[float])
| 323 | |
| 324 | |
| 325 | def receive_data(conn: Connection, length: int, deadline: Optional[float]) -> memoryview: |
| 326 | buf = bytearray(length) |
| 327 | mv = memoryview(buf) |
| 328 | bytes_read = 0 |
| 329 | # To support cancelling a network read, we shorten the socket timeout and |
| 330 | # check for the cancellation signal after each timeout. Alternatively we |
| 331 | # could close the socket but that does not reliably cancel recv() calls |
| 332 | # on all OSes. |
| 333 | # When the timeout has expired we perform one final non-blocking recv. |
| 334 | # This helps avoid spurious timeouts when the response is actually already |
| 335 | # buffered on the client. |
| 336 | orig_timeout = conn.conn.gettimeout() |
| 337 | try: |
| 338 | while bytes_read < length: |
| 339 | try: |
| 340 | # Use the legacy wait_for_read cancellation approach on PyPy due to PYTHON-5011. |
| 341 | # also use it on Windows due to PYTHON-5405 |
| 342 | if _PYPY or _WINDOWS: |
| 343 | wait_for_read(conn, deadline) |
| 344 | if _csot.get_timeout() and deadline is not None: |
| 345 | conn.set_conn_timeout(max(deadline - time.monotonic(), 0)) |
| 346 | else: |
| 347 | if deadline is not None: |
| 348 | short_timeout = min(max(deadline - time.monotonic(), 0), _POLL_TIMEOUT) |
| 349 | else: |
| 350 | short_timeout = _POLL_TIMEOUT |
| 351 | conn.set_conn_timeout(short_timeout) |
| 352 | |
| 353 | chunk_length = conn.conn.recv_into(mv[bytes_read:]) |
| 354 | except BLOCKING_IO_ERRORS: |
| 355 | if conn.cancel_context.cancelled: |
| 356 | raise _OperationCancelled("operation cancelled") from None |
| 357 | # We reached the true deadline. |
| 358 | raise socket.timeout("timed out") from None |
| 359 | except socket.timeout: |
| 360 | if conn.cancel_context.cancelled: |
| 361 | raise _OperationCancelled("operation cancelled") from None |
| 362 | if ( |
| 363 | _PYPY |
| 364 | or _WINDOWS |
| 365 | or not conn.is_sdam |
| 366 | and deadline is not None |
| 367 | and deadline - time.monotonic() < 0 |
| 368 | ): |
| 369 | # We reached the true deadline. |
| 370 | raise |
| 371 | continue |
| 372 | except OSError as exc: |
| 373 | if conn.cancel_context.cancelled: |
| 374 | raise _OperationCancelled("operation cancelled") from None |
| 375 | if _errno_from_exception(exc) == errno.EINTR: |
| 376 | continue |
| 377 | raise |
| 378 | if chunk_length == 0: |
| 379 | raise OSError("connection closed") |
| 380 | |
| 381 | bytes_read += chunk_length |
| 382 | finally: |
no test coverage detected