Blame SOURCES/Always-buffer-TCP-data-in-__handle_recv.patch

0b7e04
From c1be487bb00f2e813212031d93fcebbfbd0da60b Mon Sep 17 00:00:00 2001
0b7e04
From: Robbie Harwood <rharwood@redhat.com>
0b7e04
Date: Thu, 29 Aug 2019 11:13:41 -0400
0b7e04
Subject: [PATCH] Always buffer TCP data in __handle_recv()
0b7e04
0b7e04
Refactor __handle_recv() to always create a BytesIO() object for TCP
0b7e04
data.  Linearize control flow for ease of debugging.  Always apply
0b7e04
length checks so that we don't have to wait for EOF in the multiple-recv
0b7e04
case.
0b7e04
0b7e04
Fixes a bug where we wouldn't return any data because we never received
0b7e04
the EOF, or didn't receive it fast enough.
0b7e04
0b7e04
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
0b7e04
(cherry picked from commit 7e2b1ab27b843c220fe301b74bab01ed61b0f59a)
0b7e04
---
0b7e04
 kdcproxy/__init__.py | 54 +++++++++++++++++++++++++-------------------
0b7e04
 1 file changed, 31 insertions(+), 23 deletions(-)
0b7e04
0b7e04
diff --git a/kdcproxy/__init__.py b/kdcproxy/__init__.py
0b7e04
index 6526bc9..9bc7044 100644
0b7e04
--- a/kdcproxy/__init__.py
0b7e04
+++ b/kdcproxy/__init__.py
0b7e04
@@ -128,29 +128,37 @@ class Application:
0b7e04
             # length prefix. So add it.
0b7e04
             reply = struct.pack("!I", len(reply)) + reply
0b7e04
             return reply
0b7e04
-        else:
0b7e04
-            # TCP is a different story. The reply must be buffered
0b7e04
-            # until the full answer is accumulated.
0b7e04
-            buf = read_buffers.get(sock)
0b7e04
-            part = sock.recv(1048576)
0b7e04
-            if buf is None:
0b7e04
-                if len(part) > 4:
0b7e04
-                    # got enough data in the initial package. Now check
0b7e04
-                    # if we got the full package in the first run.
0b7e04
-                    (length, ) = struct.unpack("!I", part[0:4])
0b7e04
-                    if length + 4 == len(part):
0b7e04
-                        return part
0b7e04
-                read_buffers[sock] = buf = io.BytesIO()
0b7e04
-
0b7e04
-            if part:
0b7e04
-                # data received, accumulate it in a buffer
0b7e04
-                buf.write(part)
0b7e04
-                return None
0b7e04
-            else:
0b7e04
-                # EOF received
0b7e04
-                read_buffers.pop(sock)
0b7e04
-                reply = buf.getvalue()
0b7e04
-                return reply
0b7e04
+
0b7e04
+        # TCP is a different story. The reply must be buffered until the full
0b7e04
+        # answer is accumulated.
0b7e04
+        buf = read_buffers.get(sock)
0b7e04
+        if buf is None:
0b7e04
+            read_buffers[sock] = buf = io.BytesIO()
0b7e04
+
0b7e04
+        part = sock.recv(1048576)
0b7e04
+        if not part:
0b7e04
+            # EOF received.  Return any incomplete data we have on the theory
0b7e04
+            # that a decode error is more apparent than silent failure.  The
0b7e04
+            # client will fail faster, at least.
0b7e04
+            read_buffers.pop(sock)
0b7e04
+            reply = buf.getvalue()
0b7e04
+            return reply
0b7e04
+
0b7e04
+        # Data received, accumulate it in a buffer.
0b7e04
+        buf.write(part)
0b7e04
+
0b7e04
+        reply = buf.getvalue()
0b7e04
+        if len(reply) < 4:
0b7e04
+            # We don't have the length yet.
0b7e04
+            return None
0b7e04
+
0b7e04
+        # Got enough data to check if we have the full package.
0b7e04
+        (length, ) = struct.unpack("!I", reply[0:4])
0b7e04
+        if length + 4 == len(reply):
0b7e04
+            read_buffers.pop(sock)
0b7e04
+            return reply
0b7e04
+
0b7e04
+        return None
0b7e04
 
0b7e04
     def __filter_addr(self, addr):
0b7e04
         if addr[0] not in (socket.AF_INET, socket.AF_INET6):