From cc9d23ff3243c63baafd428f0efc17fbfb1e30e5 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Sun, 21 Oct 2018 00:59:47 +0200 Subject: [PATCH 1/6] Write data into socket without rewriting obj Fix #133 --- cheroot/makefile.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cheroot/makefile.py b/cheroot/makefile.py index bec864890c..613ad86125 100644 --- a/cheroot/makefile.py +++ b/cheroot/makefile.py @@ -64,10 +64,10 @@ def _drop(self): def write(self, data): """Sendall for non-blocking sockets.""" - while data: + payload_size = len(data) + while self.bytes_written < payload_size: try: - bytes_sent = self.send(data) - data = data[bytes_sent:] + self.send(data[self.bytes_written:]) except socket.error as e: if e.args[0] not in errors.socket_errors_nonblocking: raise From 7f4672cfa8820efb07954babed505178bd1f351f Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 22 Oct 2018 17:34:40 +0200 Subject: [PATCH 2/6] Use memoryview when writing data chunks to socket --- cheroot/_compat.py | 8 ++++++++ cheroot/makefile.py | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cheroot/_compat.py b/cheroot/_compat.py index 8be7d75198..daf0c6d1da 100644 --- a/cheroot/_compat.py +++ b/cheroot/_compat.py @@ -65,3 +65,11 @@ def assert_native(n): """ if not isinstance(n, str): raise TypeError('n must be a native str (got %s)' % type(n).__name__) + + +try: + """Python 2.7+ has memoryview builtin.""" + memoryview = memoryview +except NameError: + """Link memoryview to bytes under Python 2.6.""" + memoryview = bytes diff --git a/cheroot/makefile.py b/cheroot/makefile.py index 613ad86125..64c1581d06 100644 --- a/cheroot/makefile.py +++ b/cheroot/makefile.py @@ -15,6 +15,7 @@ import six from . import errors +from ._compat import memoryview class BufferedWriter(io.BufferedWriter): @@ -64,10 +65,11 @@ def _drop(self): def write(self, data): """Sendall for non-blocking sockets.""" - payload_size = len(data) + data_mv = memoryview(data) + payload_size = len(data_mv) while self.bytes_written < payload_size: try: - self.send(data[self.bytes_written:]) + self.send(data_mv[self.bytes_written:]) except socket.error as e: if e.args[0] not in errors.socket_errors_nonblocking: raise From c4fc520bcbbccb5ddf0fab9d2de8619de2b06268 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 22 Oct 2018 17:44:58 +0200 Subject: [PATCH 3/6] Resume sending payload even when sent == payload --- cheroot/makefile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheroot/makefile.py b/cheroot/makefile.py index 64c1581d06..69f316ab86 100644 --- a/cheroot/makefile.py +++ b/cheroot/makefile.py @@ -67,7 +67,7 @@ def write(self, data): """Sendall for non-blocking sockets.""" data_mv = memoryview(data) payload_size = len(data_mv) - while self.bytes_written < payload_size: + while self.bytes_written <= payload_size: try: self.send(data_mv[self.bytes_written:]) except socket.error as e: From e856119125f150a86f514298d7dad0b91750df4a Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 23 Oct 2018 01:21:51 +0200 Subject: [PATCH 4/6] Fix memoryview shim for Python 2 --- cheroot/_compat.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cheroot/_compat.py b/cheroot/_compat.py index daf0c6d1da..b651ac25db 100644 --- a/cheroot/_compat.py +++ b/cheroot/_compat.py @@ -67,9 +67,12 @@ def assert_native(n): raise TypeError('n must be a native str (got %s)' % type(n).__name__) -try: - """Python 2.7+ has memoryview builtin.""" +if six.PY3: + """Python 3 has memoryview builtin.""" + # Python 2.7 has it backported, but socket.write() does + # str(memoryview(b'0' * 100)) -> + # instead of accessing it correctly. memoryview = memoryview -except NameError: - """Link memoryview to bytes under Python 2.6.""" - memoryview = bytes +else: + """Link memoryview to buffer under Python 2.""" + memoryview = buffer From 26d65e8c003ea9911ef25e13aca3d6db6f9d4b41 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 23 Oct 2018 01:22:07 +0200 Subject: [PATCH 5/6] Fix bytes_sent accounting in makefile's write --- cheroot/makefile.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cheroot/makefile.py b/cheroot/makefile.py index 69f316ab86..52e66c0154 100644 --- a/cheroot/makefile.py +++ b/cheroot/makefile.py @@ -65,11 +65,12 @@ def _drop(self): def write(self, data): """Sendall for non-blocking sockets.""" + bytes_sent = 0 data_mv = memoryview(data) payload_size = len(data_mv) - while self.bytes_written <= payload_size: + while bytes_sent < payload_size: try: - self.send(data_mv[self.bytes_written:]) + bytes_sent += self.send(data_mv[bytes_sent:]) except socket.error as e: if e.args[0] not in errors.socket_errors_nonblocking: raise From 541829ddda183a08d147c5cc424018d4af11c2ca Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 23 Oct 2018 01:44:52 +0200 Subject: [PATCH 6/6] Make flake8 happy --- cheroot/_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cheroot/_compat.py b/cheroot/_compat.py index b651ac25db..670aa719fd 100644 --- a/cheroot/_compat.py +++ b/cheroot/_compat.py @@ -75,4 +75,4 @@ def assert_native(n): memoryview = memoryview else: """Link memoryview to buffer under Python 2.""" - memoryview = buffer + memoryview = buffer # noqa: F821