Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion cheroot/makefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ def __init__(self, sock, mode='r', bufsize=io.DEFAULT_BUFFER_SIZE):
def read(self, *args, **kwargs):
"""Capture bytes read."""
val = super().read(*args, **kwargs)
self.bytes_read += len(val)
# A non-blocking socket with nothing available yet can make the
# underlying BufferedReader return None instead of b''. That's
# documented io.RawIOBase behavior, so don't choke on it here.
if val is not None:
self.bytes_read += len(val)
return val

def has_data(self):
Expand Down
19 changes: 19 additions & 0 deletions cheroot/test/test_makefile.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Tests for :py:mod:`cheroot.makefile`."""

import errno

from cheroot import makefile


Expand All @@ -9,9 +11,12 @@ class MockSocket:
def __init__(self):
"""Initialize :py:class:`MockSocket`."""
self.messages = []
self.would_block = False

def recv_into(self, buf):
"""Simulate ``recv_into`` for Python 3."""
if self.would_block:
raise BlockingIOError(errno.EWOULDBLOCK, 'would block')
if not self.messages:
return 0
msg = self.messages.pop(0)
Expand Down Expand Up @@ -44,6 +49,20 @@ def test_bytes_read():
assert rfile.bytes_read == 3


def test_read_on_nonblocking_socket_with_no_data():
"""Reader should return ``None``, not crash, if nothing is available yet.

A non-blocking socket's ``read()`` can return ``None`` per the
documented ``io.RawIOBase`` contract when no data is available; this
used to blow up on ``len(None)``. Ref: cherrypy/cheroot#278
"""
sock = MockSocket()
sock.would_block = True
rfile = makefile.MakeFile(sock, 'r')
assert rfile.read(256) is None
assert rfile.bytes_read == 0


def test_bytes_written():
"""Writer should capture bytes written."""
sock = MockSocket()
Expand Down
Loading