Skip to content

Commit fcb137b

Browse files
rtm_v2 api spins in infinite loop under gevent (#1246)
* Raise an exception when reading from socket and getting no data. Returning and empty bytes object causes an infinite loop between this and the fetch function which in some cases can cause 100% cpu utilization (this happens under gevent). Also the exception handling here can't just return an empty bytes for the same reason - the now dead connection cannot be replaced by code that uses this code. * Per https://docs.python.org/3/howto/sockets.html No data means the other side has closed the connection: "When a recv returns 0 bytes, it means the other side has closed (or is in the process of closing) the connection. You will not receive any more data on this connection. Ever. You may be able to send data successfully"
1 parent e24c270 commit fcb137b

File tree

1 file changed

+12
-15
lines changed

1 file changed

+12
-15
lines changed

slack_sdk/socket_mode/builtin/internals.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import errno
21
import hashlib
32
import itertools
43
import os
@@ -24,6 +23,8 @@ def _parse_connect_response(sock: Socket) -> Tuple[Optional[int], str]:
2423
line = []
2524
while True:
2625
c = sock.recv(1)
26+
if not c:
27+
raise ConnectionError("Connection is closed")
2728
line.append(c)
2829
if c == b"\n":
2930
break
@@ -114,7 +115,10 @@ def _establish_new_socket_connection(
114115
def _read_http_response_line(sock: ssl.SSLSocket) -> str:
115116
cs = []
116117
while True:
117-
c: str = sock.recv(1).decode("utf-8")
118+
b: bytes = sock.recv(1)
119+
if not b:
120+
raise ConnectionError("Connection is closed")
121+
c: str = b.decode("utf-8")
118122
if c == "\r":
119123
break
120124
if c != "\n":
@@ -199,19 +203,12 @@ def _receive_messages(
199203
def receive(specific_buffer_size: Optional[int] = None):
200204
size = specific_buffer_size if specific_buffer_size is not None else receive_buffer_size
201205
with sock_receive_lock:
202-
try:
203-
received_bytes = sock.recv(size)
204-
if all_message_trace_enabled:
205-
if len(received_bytes) > 0:
206-
logger.debug(f"Received bytes: {received_bytes}")
207-
return received_bytes
208-
except OSError as e:
209-
# For Linux/macOS, errno.EBADF is the expected error for bad connections.
210-
# The errno.ENOTSOCK can be sent when running on Windows OS.
211-
if e.errno in (errno.EBADF, errno.ENOTSOCK):
212-
logger.debug("The connection seems to be already closed.")
213-
return bytes()
214-
raise e
206+
received_bytes = sock.recv(size)
207+
if not received_bytes:
208+
raise ConnectionError("Connection is closed")
209+
if all_message_trace_enabled:
210+
logger.debug(f"Received bytes: {received_bytes}")
211+
return received_bytes
215212

216213
return _fetch_messages(
217214
messages=[],

0 commit comments

Comments
 (0)