-   Notifications  You must be signed in to change notification settings 
- Fork 750
bugfix telnet server: prompt app not cancelled when client close connection #1585
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
Conversation
If client closes the telnet connection (either due to user typing "Ctrl-] then 'quit'" or due to network shutdown) in middle of the prompt application, the application will hang forever and resources maintained in TelnetServer.connections and TelnetServer._application_tasks are not released.
| Hi @wuf, Thanks for reporting the issue and proposing this patch! The underlying issue is more complex, and it looks like there are a couple of bugs. Some things here that I notice: 
 I hope this is sufficient as feedback to set the direction. I can't merge it as-is unfortunately. I'll see whether I can already take care of some bullet points here. | 
The makes context managers of the following: - `create_pipe_input()` - `PosixPipeInput` - `Win32PipeInput` The reason for this change is that the close method of the pipe should only close the write-end, and as a consequence of that, the read-end should trigger a `EOFError`. Before this change, the read-end was also closed, and that caused the key input to never wake up and "read" the end-of-file. However, we still want to close the read end at some point, and that's why this is a context manager now. As part of this change, exceptions that are raised in the TelnetServer interact method, won't cause cause the whole server to crash. See also: #1585
The makes context managers of the following: - `create_pipe_input()` - `PosixPipeInput` - `Win32PipeInput` The reason for this change is that the close method of the pipe should only close the write-end, and as a consequence of that, the read-end should trigger a `EOFError`. Before this change, the read-end was also closed, and that caused the key input to never wake up and "read" the end-of-file. However, we still want to close the read end at some point, and that's why this is a context manager now. As part of this change, exceptions that are raised in the TelnetServer interact method, won't cause cause the whole server to crash. See also: #1585
The makes context managers of the following: - `create_pipe_input()` - `PosixPipeInput` - `Win32PipeInput` The reason for this change is that the close method of the pipe should only close the write-end, and as a consequence of that, the read-end should trigger a `EOFError`. Before this change, the read-end was also closed, and that caused the key input to never wake up and "read" the end-of-file. However, we still want to close the read end at some point, and that's why this is a context manager now. As part of this change, exceptions that are raised in the TelnetServer interact method, won't cause cause the whole server to crash. See also: #1585
The makes context managers of the following: - `create_pipe_input()` - `PosixPipeInput` - `Win32PipeInput` The reason for this change is that the close method of the pipe should only close the write-end, and as a consequence of that, the read-end should trigger a `EOFError`. Before this change, the read-end was also closed, and that caused the key input to never wake up and "read" the end-of-file. However, we still want to close the read end at some point, and that's why this is a context manager now. As part of this change, exceptions that are raised in the TelnetServer interact method, won't cause cause the whole server to crash. See also: #1585
The makes context managers of the following: - `create_pipe_input()` - `PosixPipeInput` - `Win32PipeInput` The reason for this change is that the close method of the pipe should only close the write-end, and as a consequence of that, the read-end should trigger a `EOFError`. Before this change, the read-end was also closed, and that caused the key input to never wake up and "read" the end-of-file. However, we still want to close the read end at some point, and that's why this is a context manager now. As part of this change, exceptions that are raised in the TelnetServer interact method, won't cause cause the whole server to crash. See also: #1585
| thanks for the quick reply. Yes, I totally agree with your points and this should be fixed at PosixPipeInput. I once raised the PosixPipe issue #1522 to report this but I can only provide an ugly demo at that time. Gald that this issue is finally noticed and a mature fix is provided by you. I will try it in my application, thanks. | 
| Your patch works, below are a few things that I noticed, 
 
 | 
The makes context managers of the following: - `create_pipe_input()` - `PosixPipeInput` - `Win32PipeInput` The reason for this change is that the close method of the pipe should only close the write-end, and as a consequence of that, the read-end should trigger a `EOFError`. Before this change, the read-end was also closed, and that caused the key input to never wake up and "read" the end-of-file. However, we still want to close the read end at some point, and that's why this is a context manager now. As part of this change, exceptions that are raised in the TelnetServer interact method, won't cause cause the whole server to crash. See also: #1585 Co-Author: Frank Wu <kwyd@163.com>
| @wuf: Thanks for the very quick reply! 
 | 
This makes context managers of the following: - `create_pipe_input()` - `PosixPipeInput` - `Win32PipeInput` The reason for this change is that the close method of the pipe should only close the write-end, and as a consequence of that, the read-end should trigger an `EOFError`. Before this change, the read-end was also closed, and that caused the key input to never wake up and "read" the end-of-file. However, we still want to close the read end at some point, and that's why this is a context manager now. As part of this change, exceptions that are raised in the TelnetServer interact method, won't cause cause the whole server to crash. See also: #1585 Co-Author: Frank Wu <kwyd@163.com>
This makes context managers of the following: - `create_pipe_input()` - `PosixPipeInput` - `Win32PipeInput` The reason for this change is that the close method of the pipe should only close the write-end, and as a consequence of that, the read-end should trigger an `EOFError`. Before this change, the read-end was also closed, and that caused the key input to never wake up and "read" the end-of-file. However, we still want to close the read end at some point, and that's why this is a context manager now. As part of this change, exceptions that are raised in the TelnetServer interact method, won't cause cause the whole server to crash. See also: #1585 Co-Author: Frank Wu <kwyd@163.com>
| @wuf: I merged my branch (I made you co-author in the commit message). Feel free to still comment, if there is anything. | 
| 
 how about below patch diff --git a/prompt_toolkit/contrib/telnet/server.py b/prompt_toolkit/contrib/telnet/server.py index 035239d2..227fc1fe 100644 --- a/prompt_toolkit/contrib/telnet/server.py +++ b/prompt_toolkit/contrib/telnet/server.py @@ -99,7 +99,8 @@ class _ConnectionStdout: def flush(self) -> None: try: - self._connection.send(b"".join(self._buffer)) + if not self._closed: + self._connection.send(b"".join(self._buffer)) except OSError as e: logger.warning("Couldn't send data over socket: %s" % e) @@ -355,6 +356,9 @@ class TelnetServer: finally: self.connections.remove(connection) logger.info("Stopping interaction %r %r", *addr) + except EOFError: + # caused by "Connection closed by client" + pass except BaseException as e: print("Got %s" % type(e).__name__, e) import traceback  | 
| I'm closing this. Thanks again @wuf! | 
If client closes the telnet connection (either due to user typing
"Ctrl-] then 'quit'" or due to network shutdown) in middle of the
prompt application, the application will hang forever and resources
maintained in TelnetServer.connections and
TelnetServer._application_tasks are not released.