vmagamedov / grpclib

Pure-Python gRPC implementation for asyncio
http://grpclib.readthedocs.io
BSD 3-Clause "New" or "Revised" License
936 stars 92 forks source link

AttributeError raised when server closes the connection #185

Closed khodedawsh closed 5 months ago

khodedawsh commented 7 months ago

So I was trying to use a ssl context on server side to verify the client, and noticed when there is a mismatch in client certificates the server closes the connection (as it should)

however on the client side I'm getting the following traceback:

Traceback (most recent call last):
  File "/home/dawsh/Documents/grpclib/.venv/lib/python3.11/site-packages/grpclib/client.py", line 368, in recv_initial_metadata
    headers = await self._stream.recv_headers()
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/dawsh/Documents/grpclib/.venv/lib/python3.11/site-packages/grpclib/protocol.py", line 342, in recv_headers
    await self.headers_received.wait()
  File "/usr/lib/python3.11/asyncio/locks.py", line 213, in wait
    await fut
asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/dawsh/Documents/grpclib/.venv/lib/python3.11/site-packages/grpclib/client.py", line 904, in __call__
    reply = await stream.recv_message()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/dawsh/Documents/grpclib/.venv/lib/python3.11/site-packages/grpclib/client.py", line 425, in recv_message
    await self.recv_initial_metadata()
  File "/home/dawsh/Documents/grpclib/.venv/lib/python3.11/site-packages/grpclib/client.py", line 367, in recv_initial_metadata
    with self._wrapper:
  File "/home/dawsh/Documents/grpclib/.venv/lib/python3.11/site-packages/grpclib/utils.py", line 70, in __exit__
    raise self._error
grpclib.exceptions.StreamTerminatedError: Connection lost

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/dawsh/Documents/grpclib/client.py", line 43, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/user/Documents/grpclib/client.py", line 37, in main
    response = await stub.Check(HealthCheckRequest())
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/dawsh/Documents/grpclib/.venv/lib/python3.11/site-packages/gr
pclib/client.py", line 902, in __call__
    async with self.open(timeout=timeout, metadata=metadata) as stream:
  File "/home/dawsh/Documents/grpclib/.venv/lib/python3.11/site-packages/grpclib/client.py", line 566, in __aexit__
    self._stream.reset_nowait()
  File "/home/dawsh/Documents/grpclib/.venv/lib/python3.11/site-packages/grpclib/protocol.py", line 468, in reset_nowait
    self._transport.write(self._h2_connection.data_to_send())
  File "/usr/lib/python3.11/asyncio/sslproto.py", line 218, in write
    self._ssl_protocol._write_appdata((data,))
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute '_write_appdata'

using grpclib 0.4.7, this is the same as the mtls example but with the client certificate seperated and modified. now I know I can't catch the StreamTerminatedError and I don't think It's good practice to catch an AttributeError either.

vmagamedov commented 5 months ago

Fixed in 5916cba69fc1f8a25fe8e749e3c4427897b3d228. Now you will get grpclib.exceptions.StreamTerminatedError: Connection lost on the client-side.