Skip to content

Commit 633c5e5

Browse files
nik-localstackGitHub Copilot
andcommitted
fix(postgresql-proxy): prevent SSL COPY stalls by draining nonblocking reads
Co-authored-by: GitHub Copilot <copilot@github.com>
1 parent 37a1fee commit 633c5e5

1 file changed

Lines changed: 12 additions & 0 deletions

File tree

postgresql_proxy/proxy.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ def accept_wrapper(self, sock: socket.socket):
130130

131131
# Accept the raw connection
132132
clientsocket, address = sock.accept()
133+
# On macOS, accepted sockets inherit O_NONBLOCK from the listening socket.
134+
# SSL negotiation uses blocking recv, so we must set blocking explicitly here.
135+
clientsocket.setblocking(True)
133136

134137
# Check if SSL is enabled for this proxy
135138
if self.ssl_context:
@@ -234,6 +237,15 @@ def service_connection(self, key: SelectorKeyProxy, mask):
234237
if recv_data:
235238
LOG.debug('%s received data:\n%s', conn.name, recv_data)
236239
conn.received(recv_data)
240+
# excerpt from https://docs.python.org/3/library/ssl.html#ssl-nonblocking
241+
# Conversely, since the SSL layer has its own framing, a SSL socket may still have data available
242+
# for reading without select() being aware of it. Therefore, you should first call SSLSocket.recv()
243+
# to drain any potentially available data, and then only block on a select() call if still necessary.
244+
while isinstance(sock, ssl.SSLSocket) and sock.pending() > 0:
245+
extra = sock.recv(4096)
246+
if extra:
247+
LOG.debug('%s received pending SSL data:\n%s', conn.name, extra)
248+
conn.received(extra)
237249
else:
238250
self._unregister_conn(conn)
239251
LOG.debug('%s connection closing %s', conn.name, conn.address)

0 commit comments

Comments
 (0)