yt-local/python/gevent/_socket3.py
2018-07-12 23:41:07 -07:00

1066 lines
39 KiB
Python

# Port of Python 3.3's socket module to gevent
"""
Python 3 socket module.
"""
# Our import magic sadly makes this warning useless
# pylint: disable=undefined-variable
# pylint: disable=too-many-statements,too-many-branches
# pylint: disable=too-many-public-methods,unused-argument
from __future__ import absolute_import
import io
import os
import sys
import time
from gevent import _socketcommon
from gevent._util import copy_globals
from gevent._compat import PYPY
import _socket
from os import dup
copy_globals(_socketcommon, globals(),
names_to_ignore=_socketcommon.__extensions__,
dunder_names_to_keep=())
__socket__ = _socketcommon.__socket__
__implements__ = _socketcommon._implements
__extensions__ = _socketcommon.__extensions__
__imports__ = _socketcommon.__imports__
__dns__ = _socketcommon.__dns__
SocketIO = __socket__.SocketIO # pylint:disable=no-member
def _get_memory(data):
mv = memoryview(data)
if mv.shape:
return mv
# No shape, probably working with a ctypes object,
# or something else exotic that supports the buffer interface
return mv.tobytes()
timeout_default = object()
class _wrefsocket(_socket.socket):
# Plain stdlib socket.socket objects subclass _socket.socket
# and add weakref ability. The ssl module, for one, counts on this.
# We don't create socket.socket objects (because they may have been
# monkey patched to be the object from this module), but we still
# need to make sure what we do create can be weakrefd.
__slots__ = ("__weakref__", )
if PYPY:
# server.py unwraps the socket object to get the raw _sock;
# it depends on having a timeout property alias, which PyPy does not
# provide.
timeout = property(lambda s: s.gettimeout(),
lambda s, nv: s.settimeout(nv))
class socket(object):
"""
gevent `socket.socket <https://docs.python.org/3/library/socket.html#socket-objects>`_
for Python 3.
This object should have the same API as the standard library socket linked to above. Not all
methods are specifically documented here; when they are they may point out a difference
to be aware of or may document a method the standard library does not.
"""
# Subclasses can set this to customize the type of the
# native _socket.socket we create. It MUST be a subclass
# of _wrefsocket. (gevent internal usage only)
_gevent_sock_class = _wrefsocket
def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
# Take the same approach as socket2: wrap a real socket object,
# don't subclass it. This lets code that needs the raw _sock (not tied to the hub)
# get it. This shows up in tests like test__example_udp_server.
self._sock = self._gevent_sock_class(family, type, proto, fileno)
self._io_refs = 0
self._closed = False
_socket.socket.setblocking(self._sock, False)
fileno = _socket.socket.fileno(self._sock)
self.hub = get_hub()
io_class = self.hub.loop.io
self._read_event = io_class(fileno, 1)
self._write_event = io_class(fileno, 2)
self.timeout = _socket.getdefaulttimeout()
def __getattr__(self, name):
return getattr(self._sock, name)
if hasattr(_socket, 'SOCK_NONBLOCK'):
# Only defined under Linux
@property
def type(self):
# See https://github.com/gevent/gevent/pull/399
if self.timeout != 0.0:
return self._sock.type & ~_socket.SOCK_NONBLOCK # pylint:disable=no-member
return self._sock.type
def __enter__(self):
return self
def __exit__(self, *args):
if not self._closed:
self.close()
def __repr__(self):
"""Wrap __repr__() to reveal the real class name."""
try:
s = _socket.socket.__repr__(self._sock)
except Exception as ex: # pylint:disable=broad-except
# Observed on Windows Py3.3, printing the repr of a socket
# that just sufferred a ConnectionResetError [WinError 10054]:
# "OverflowError: no printf formatter to display the socket descriptor in decimal"
# Not sure what the actual cause is or if there's a better way to handle this
s = '<socket [%r]>' % ex
if s.startswith("<socket object"):
s = "<%s.%s%s%s" % (self.__class__.__module__,
self.__class__.__name__,
getattr(self, '_closed', False) and " [closed] " or "",
s[7:])
return s
def __getstate__(self):
raise TypeError("Cannot serialize socket object")
def _get_ref(self):
return self._read_event.ref or self._write_event.ref
def _set_ref(self, value):
self._read_event.ref = value
self._write_event.ref = value
ref = property(_get_ref, _set_ref)
def _wait(self, watcher, timeout_exc=timeout('timed out')):
"""Block the current greenlet until *watcher* has pending events.
If *timeout* is non-negative, then *timeout_exc* is raised after *timeout* second has passed.
By default *timeout_exc* is ``socket.timeout('timed out')``.
If :func:`cancel_wait` is called, raise ``socket.error(EBADF, 'File descriptor was closed in another greenlet')``.
"""
if watcher.callback is not None:
raise _socketcommon.ConcurrentObjectUseError('This socket is already used by another greenlet: %r' % (watcher.callback, ))
if self.timeout is not None:
timeout = Timeout.start_new(self.timeout, timeout_exc, ref=False)
else:
timeout = None
try:
self.hub.wait(watcher)
finally:
if timeout is not None:
timeout.cancel()
def dup(self):
"""dup() -> socket object
Return a new socket object connected to the same system resource.
"""
fd = dup(self.fileno())
sock = self.__class__(self.family, self.type, self.proto, fileno=fd)
sock.settimeout(self.gettimeout())
return sock
def accept(self):
"""accept() -> (socket object, address info)
Wait for an incoming connection. Return a new socket
representing the connection, and the address of the client.
For IP sockets, the address info is a pair (hostaddr, port).
"""
while True:
try:
fd, addr = self._accept()
break
except BlockingIOError:
if self.timeout == 0.0:
raise
self._wait(self._read_event)
sock = socket(self.family, self.type, self.proto, fileno=fd)
# Python Issue #7995: if no default timeout is set and the listening
# socket had a (non-zero) timeout, force the new socket in blocking
# mode to override platform-specific socket flags inheritance.
# XXX do we need to do this?
if getdefaulttimeout() is None and self.gettimeout():
sock.setblocking(True)
return sock, addr
def makefile(self, mode="r", buffering=None, *,
encoding=None, errors=None, newline=None):
"""Return an I/O stream connected to the socket
The arguments are as for io.open() after the filename,
except the only mode characters supported are 'r', 'w' and 'b'.
The semantics are similar too.
"""
# (XXX refactor to share code?)
for c in mode:
if c not in {"r", "w", "b"}:
raise ValueError("invalid mode %r (only r, w, b allowed)")
writing = "w" in mode
reading = "r" in mode or not writing
assert reading or writing
binary = "b" in mode
rawmode = ""
if reading:
rawmode += "r"
if writing:
rawmode += "w"
raw = SocketIO(self, rawmode)
self._io_refs += 1
if buffering is None:
buffering = -1
if buffering < 0:
buffering = io.DEFAULT_BUFFER_SIZE
if buffering == 0:
if not binary:
raise ValueError("unbuffered streams must be binary")
return raw
if reading and writing:
buffer = io.BufferedRWPair(raw, raw, buffering)
elif reading:
buffer = io.BufferedReader(raw, buffering)
else:
assert writing
buffer = io.BufferedWriter(raw, buffering)
if binary:
return buffer
text = io.TextIOWrapper(buffer, encoding, errors, newline)
text.mode = mode
return text
def _decref_socketios(self):
if self._io_refs > 0:
self._io_refs -= 1
if self._closed:
self.close()
def _real_close(self, _ss=_socket.socket, cancel_wait_ex=cancel_wait_ex):
# This function should not reference any globals. See Python issue #808164.
self.hub.cancel_wait(self._read_event, cancel_wait_ex)
self.hub.cancel_wait(self._write_event, cancel_wait_ex)
_ss.close(self._sock)
# Break any references to the underlying socket object. Tested
# by test__refcount. (Why does this matter?). Be sure to
# preserve our same family/type/proto if possible (if we
# don't, we can get TypeError instead of OSError; see
# test_socket.SendmsgUDP6Test.testSendmsgAfterClose)... but
# this isn't always possible (see test_socket.test_unknown_socket_family_repr)
# TODO: Can we use a simpler proxy, like _socket2 does?
try:
self._sock = self._gevent_sock_class(self.family, self.type, self.proto)
except OSError:
pass
else:
_ss.close(self._sock)
def close(self):
# This function should not reference any globals. See Python issue #808164.
self._closed = True
if self._io_refs <= 0:
self._real_close()
@property
def closed(self):
return self._closed
def detach(self):
"""detach() -> file descriptor
Close the socket object without closing the underlying file descriptor.
The object cannot be used after this call, but the file descriptor
can be reused for other purposes. The file descriptor is returned.
"""
self._closed = True
return self._sock.detach()
def connect(self, address):
if self.timeout == 0.0:
return _socket.socket.connect(self._sock, address)
if isinstance(address, tuple):
r = getaddrinfo(address[0], address[1], self.family)
address = r[0][-1]
if self.timeout is not None:
timer = Timeout.start_new(self.timeout, timeout('timed out'))
else:
timer = None
try:
while True:
err = self.getsockopt(SOL_SOCKET, SO_ERROR)
if err:
raise error(err, strerror(err))
result = _socket.socket.connect_ex(self._sock, address)
if not result or result == EISCONN:
break
elif (result in (EWOULDBLOCK, EINPROGRESS, EALREADY)) or (result == EINVAL and is_windows):
self._wait(self._write_event)
else:
raise error(result, strerror(result))
finally:
if timer is not None:
timer.cancel()
def connect_ex(self, address):
try:
return self.connect(address) or 0
except timeout:
return EAGAIN
except gaierror:
# gaierror/overflowerror/typerror is not silenced by connect_ex;
# gaierror extends OSError (aka error) so catch it first
raise
except error as ex:
# error is now OSError and it has various subclasses.
# Only those that apply to actually connecting are silenced by
# connect_ex.
if ex.errno:
return ex.errno
raise # pragma: no cover
def recv(self, *args):
while True:
try:
return _socket.socket.recv(self._sock, *args)
except error as ex:
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
raise
self._wait(self._read_event)
if hasattr(_socket.socket, 'sendmsg'):
# Only on Unix
def recvmsg(self, *args):
while True:
try:
return _socket.socket.recvmsg(self._sock, *args)
except error as ex:
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
raise
self._wait(self._read_event)
def recvmsg_into(self, *args):
while True:
try:
return _socket.socket.recvmsg_into(self._sock, *args)
except error as ex:
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
raise
self._wait(self._read_event)
def recvfrom(self, *args):
while True:
try:
return _socket.socket.recvfrom(self._sock, *args)
except error as ex:
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
raise
self._wait(self._read_event)
def recvfrom_into(self, *args):
while True:
try:
return _socket.socket.recvfrom_into(self._sock, *args)
except error as ex:
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
raise
self._wait(self._read_event)
def recv_into(self, *args):
while True:
try:
return _socket.socket.recv_into(self._sock, *args)
except error as ex:
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
raise
self._wait(self._read_event)
def send(self, data, flags=0, timeout=timeout_default):
if timeout is timeout_default:
timeout = self.timeout
try:
return _socket.socket.send(self._sock, data, flags)
except error as ex:
if ex.args[0] != EWOULDBLOCK or timeout == 0.0:
raise
self._wait(self._write_event)
try:
return _socket.socket.send(self._sock, data, flags)
except error as ex2:
if ex2.args[0] == EWOULDBLOCK:
return 0
raise
def sendall(self, data, flags=0):
# XXX Now that we run on PyPy3, see the notes in _socket2.py's sendall()
# and implement that here if needed.
# PyPy3 is not optimized for performance yet, and is known to be slower than
# PyPy2, so it's possibly premature to do this. However, there is a 3.5 test case that
# possibly exposes this in a severe way.
data_memory = _get_memory(data)
len_data_memory = len(data_memory)
if not len_data_memory:
# Don't try to send empty data at all, no point, and breaks ssl
# See issue 719
return 0
if self.timeout is None:
data_sent = 0
while data_sent < len_data_memory:
data_sent += self.send(data_memory[data_sent:], flags)
else:
timeleft = self.timeout
end = time.time() + timeleft
data_sent = 0
while True:
data_sent += self.send(data_memory[data_sent:], flags, timeout=timeleft)
if data_sent >= len_data_memory:
break
timeleft = end - time.time()
if timeleft <= 0:
raise timeout('timed out')
def sendto(self, *args):
try:
return _socket.socket.sendto(self._sock, *args)
except error as ex:
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
raise
self._wait(self._write_event)
try:
return _socket.socket.sendto(self._sock, *args)
except error as ex2:
if ex2.args[0] == EWOULDBLOCK:
return 0
raise
if hasattr(_socket.socket, 'sendmsg'):
# Only on Unix
def sendmsg(self, buffers, ancdata=(), flags=0, address=None):
try:
return _socket.socket.sendmsg(self._sock, buffers, ancdata, flags, address)
except error as ex:
if flags & getattr(_socket, 'MSG_DONTWAIT', 0):
# Enable non-blocking behaviour
# XXX: Do all platforms that have sendmsg have MSG_DONTWAIT?
raise
if ex.args[0] != EWOULDBLOCK or self.timeout == 0.0:
raise
self._wait(self._write_event)
try:
return _socket.socket.sendmsg(self._sock, buffers, ancdata, flags, address)
except error as ex2:
if ex2.args[0] == EWOULDBLOCK:
return 0
raise
def setblocking(self, flag):
if flag:
self.timeout = None
else:
self.timeout = 0.0
def settimeout(self, howlong):
if howlong is not None:
try:
f = howlong.__float__
except AttributeError:
raise TypeError('a float is required')
howlong = f()
if howlong < 0.0:
raise ValueError('Timeout value out of range')
self.__dict__['timeout'] = howlong
def gettimeout(self):
return self.__dict__['timeout']
def shutdown(self, how):
if how == 0: # SHUT_RD
self.hub.cancel_wait(self._read_event, cancel_wait_ex)
elif how == 1: # SHUT_WR
self.hub.cancel_wait(self._write_event, cancel_wait_ex)
else:
self.hub.cancel_wait(self._read_event, cancel_wait_ex)
self.hub.cancel_wait(self._write_event, cancel_wait_ex)
self._sock.shutdown(how)
# sendfile: new in 3.5. But there's no real reason to not
# support it everywhere. Note that we can't use os.sendfile()
# because it's not cooperative.
def _sendfile_use_sendfile(self, file, offset=0, count=None):
# This is called directly by tests
raise __socket__._GiveupOnSendfile() # pylint:disable=no-member
def _sendfile_use_send(self, file, offset=0, count=None):
self._check_sendfile_params(file, offset, count)
if self.gettimeout() == 0:
raise ValueError("non-blocking sockets are not supported")
if offset:
file.seek(offset)
blocksize = min(count, 8192) if count else 8192
total_sent = 0
# localize variable access to minimize overhead
file_read = file.read
sock_send = self.send
try:
while True:
if count:
blocksize = min(count - total_sent, blocksize)
if blocksize <= 0:
break
data = memoryview(file_read(blocksize))
if not data:
break # EOF
while True:
try:
sent = sock_send(data)
except BlockingIOError:
continue
else:
total_sent += sent
if sent < len(data):
data = data[sent:]
else:
break
return total_sent
finally:
if total_sent > 0 and hasattr(file, 'seek'):
file.seek(offset + total_sent)
def _check_sendfile_params(self, file, offset, count):
if 'b' not in getattr(file, 'mode', 'b'):
raise ValueError("file should be opened in binary mode")
if not self.type & SOCK_STREAM:
raise ValueError("only SOCK_STREAM type sockets are supported")
if count is not None:
if not isinstance(count, int):
raise TypeError(
"count must be a positive integer (got {!r})".format(count))
if count <= 0:
raise ValueError(
"count must be a positive integer (got {!r})".format(count))
def sendfile(self, file, offset=0, count=None):
"""sendfile(file[, offset[, count]]) -> sent
Send a file until EOF is reached by using high-performance
os.sendfile() and return the total number of bytes which
were sent.
*file* must be a regular file object opened in binary mode.
If os.sendfile() is not available (e.g. Windows) or file is
not a regular file socket.send() will be used instead.
*offset* tells from where to start reading the file.
If specified, *count* is the total number of bytes to transmit
as opposed to sending the file until EOF is reached.
File position is updated on return or also in case of error in
which case file.tell() can be used to figure out the number of
bytes which were sent.
The socket must be of SOCK_STREAM type.
Non-blocking sockets are not supported.
.. versionadded:: 1.1rc4
Added in Python 3.5, but available under all Python 3 versions in
gevent.
"""
return self._sendfile_use_send(file, offset, count)
# get/set_inheritable new in 3.4
if hasattr(os, 'get_inheritable') or hasattr(os, 'get_handle_inheritable'):
# pylint:disable=no-member
if os.name == 'nt':
def get_inheritable(self):
return os.get_handle_inheritable(self.fileno())
def set_inheritable(self, inheritable):
os.set_handle_inheritable(self.fileno(), inheritable)
else:
def get_inheritable(self):
return os.get_inheritable(self.fileno())
def set_inheritable(self, inheritable):
os.set_inheritable(self.fileno(), inheritable)
_added = "\n\n.. versionadded:: 1.1rc4 Added in Python 3.4"
get_inheritable.__doc__ = "Get the inheritable flag of the socket" + _added
set_inheritable.__doc__ = "Set the inheritable flag of the socket" + _added
del _added
if sys.version_info[:2] == (3, 4) and sys.version_info[:3] <= (3, 4, 2):
# Python 3.4, up to and including 3.4.2, had a bug where the
# SocketType enumeration overwrote the SocketType class imported
# from _socket. This was fixed in 3.4.3 (http://bugs.python.org/issue20386
# and https://github.com/python/cpython/commit/0d2f85f38a9691efdfd1e7285c4262cab7f17db7).
# Prior to that, if we replace SocketType with our own class, the implementation
# of socket.type breaks with "OSError: [Errno 97] Address family not supported by protocol".
# Therefore, on these old versions, we must preserve it as an enum; while this
# seems like it could lead to non-green behaviour, code on those versions
# cannot possibly be using SocketType as a class anyway.
SocketType = __socket__.SocketType # pylint:disable=no-member
# Fixup __all__; note that we get exec'd multiple times during unit tests
if 'SocketType' in __implements__:
__implements__.remove('SocketType')
if 'SocketType' not in __imports__:
__imports__.append('SocketType')
else:
SocketType = socket
def fromfd(fd, family, type, proto=0):
""" fromfd(fd, family, type[, proto]) -> socket object
Create a socket object from a duplicate of the given file
descriptor. The remaining arguments are the same as for socket().
"""
nfd = dup(fd)
return socket(family, type, proto, nfd)
if hasattr(_socket.socket, "share"):
def fromshare(info):
""" fromshare(info) -> socket object
Create a socket object from a the bytes object returned by
socket.share(pid).
"""
return socket(0, 0, 0, info)
__implements__.append('fromshare')
if hasattr(_socket, "socketpair"):
def socketpair(family=None, type=SOCK_STREAM, proto=0):
"""socketpair([family[, type[, proto]]]) -> (socket object, socket object)
Create a pair of socket objects from the sockets returned by the platform
socketpair() function.
The arguments are the same as for socket() except the default family is
AF_UNIX if defined on the platform; otherwise, the default is AF_INET.
.. versionchanged:: 1.2
All Python 3 versions on Windows supply this function (natively
supplied by Python 3.5 and above).
"""
if family is None:
try:
family = AF_UNIX
except NameError:
family = AF_INET
a, b = _socket.socketpair(family, type, proto)
a = socket(family, type, proto, a.detach())
b = socket(family, type, proto, b.detach())
return a, b
else:
# Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain.
# gevent: taken from 3.6 release. Expected to be used only on Win. Added to Win/3.5
# gevent: for < 3.5, pass the default value of 128 to lsock.listen()
# (3.5+ uses this as a default and the original code passed no value)
_LOCALHOST = '127.0.0.1'
_LOCALHOST_V6 = '::1'
def socketpair(family=AF_INET, type=SOCK_STREAM, proto=0):
if family == AF_INET:
host = _LOCALHOST
elif family == AF_INET6:
host = _LOCALHOST_V6
else:
raise ValueError("Only AF_INET and AF_INET6 socket address families "
"are supported")
if type != SOCK_STREAM:
raise ValueError("Only SOCK_STREAM socket type is supported")
if proto != 0:
raise ValueError("Only protocol zero is supported")
# We create a connected TCP socket. Note the trick with
# setblocking(False) that prevents us from having to create a thread.
lsock = socket(family, type, proto)
try:
lsock.bind((host, 0))
lsock.listen(128)
# On IPv6, ignore flow_info and scope_id
addr, port = lsock.getsockname()[:2]
csock = socket(family, type, proto)
try:
csock.setblocking(False)
try:
csock.connect((addr, port))
except (BlockingIOError, InterruptedError):
pass
csock.setblocking(True)
ssock, _ = lsock.accept()
except:
csock.close()
raise
finally:
lsock.close()
return (ssock, csock)
if sys.version_info[:2] < (3, 5):
# Not provided natively
if 'socketpair' in __implements__:
# Multiple imports can cause this to be missing if _socketcommon
# was successfully imported, leading to subsequent imports to cause
# ValueError
__implements__.remove('socketpair')
# PyPy needs drop and reuse
def _do_reuse_or_drop(sock, methname):
try:
method = getattr(sock, methname)
except (AttributeError, TypeError):
pass
else:
method()
from io import BytesIO
class _basefileobject(object):
"""Faux file object attached to a socket object."""
default_bufsize = 8192
name = "<socket>"
__slots__ = ["mode", "bufsize", "softspace",
# "closed" is a property, see below
"_sock", "_rbufsize", "_wbufsize", "_rbuf", "_wbuf", "_wbuf_len",
"_close"]
def __init__(self, sock, mode='rb', bufsize=-1, close=False):
_do_reuse_or_drop(sock, '_reuse')
self._sock = sock
self.mode = mode # Not actually used in this version
if bufsize < 0:
bufsize = self.default_bufsize
self.bufsize = bufsize
self.softspace = False
# _rbufsize is the suggested recv buffer size. It is *strictly*
# obeyed within readline() for recv calls. If it is larger than
# default_bufsize it will be used for recv calls within read().
if bufsize == 0:
self._rbufsize = 1
elif bufsize == 1:
self._rbufsize = self.default_bufsize
else:
self._rbufsize = bufsize
self._wbufsize = bufsize
# We use BytesIO for the read buffer to avoid holding a list
# of variously sized string objects which have been known to
# fragment the heap due to how they are malloc()ed and often
# realloc()ed down much smaller than their original allocation.
self._rbuf = BytesIO()
self._wbuf = [] # A list of strings
self._wbuf_len = 0
self._close = close
def _getclosed(self):
return self._sock is None
closed = property(_getclosed, doc="True if the file is closed")
def close(self):
try:
if self._sock:
self.flush()
finally:
s = self._sock
self._sock = None
if s is not None:
if self._close:
s.close()
else:
_do_reuse_or_drop(s, '_drop')
def __del__(self):
try:
self.close()
except: # pylint:disable=bare-except
# close() may fail if __init__ didn't complete
pass
def flush(self):
if self._wbuf:
data = b"".join(self._wbuf)
self._wbuf = []
self._wbuf_len = 0
buffer_size = max(self._rbufsize, self.default_bufsize)
data_size = len(data)
write_offset = 0
view = memoryview(data)
try:
while write_offset < data_size:
self._sock.sendall(view[write_offset:write_offset + buffer_size])
write_offset += buffer_size
finally:
if write_offset < data_size:
remainder = data[write_offset:]
del view, data # explicit free
self._wbuf.append(remainder)
self._wbuf_len = len(remainder)
def fileno(self):
return self._sock.fileno()
def write(self, data):
if not isinstance(data, bytes):
raise TypeError("Non-bytes data")
if not data:
return
self._wbuf.append(data)
self._wbuf_len += len(data)
if (self._wbufsize == 0 or (self._wbufsize == 1 and b'\n' in data) or
(self._wbufsize > 1 and self._wbuf_len >= self._wbufsize)):
self.flush()
def writelines(self, list):
# XXX We could do better here for very long lists
# XXX Should really reject non-string non-buffers
lines = filter(None, map(str, list))
self._wbuf_len += sum(map(len, lines))
self._wbuf.extend(lines)
if self._wbufsize <= 1 or self._wbuf_len >= self._wbufsize:
self.flush()
def read(self, size=-1):
# Use max, disallow tiny reads in a loop as they are very inefficient.
# We never leave read() with any leftover data from a new recv() call
# in our internal buffer.
rbufsize = max(self._rbufsize, self.default_bufsize)
# Our use of BytesIO rather than lists of string objects returned by
# recv() minimizes memory usage and fragmentation that occurs when
# rbufsize is large compared to the typical return value of recv().
buf = self._rbuf
buf.seek(0, 2) # seek end
if size < 0:
# Read until EOF
self._rbuf = BytesIO() # reset _rbuf. we consume it via buf.
while True:
try:
data = self._sock.recv(rbufsize)
except InterruptedError:
continue
if not data:
break
buf.write(data)
return buf.getvalue()
else:
# Read until size bytes or EOF seen, whichever comes first
buf_len = buf.tell()
if buf_len >= size:
# Already have size bytes in our buffer? Extract and return.
buf.seek(0)
rv = buf.read(size)
self._rbuf = BytesIO()
self._rbuf.write(buf.read())
return rv
self._rbuf = BytesIO() # reset _rbuf. we consume it via buf.
while True:
left = size - buf_len
# recv() will malloc the amount of memory given as its
# parameter even though it often returns much less data
# than that. The returned data string is short lived
# as we copy it into a BytesIO and free it. This avoids
# fragmentation issues on many platforms.
try:
data = self._sock.recv(left)
except InterruptedError:
continue
if not data:
break
n = len(data)
if n == size and not buf_len:
# Shortcut. Avoid buffer data copies when:
# - We have no data in our buffer.
# AND
# - Our call to recv returned exactly the
# number of bytes we were asked to read.
return data
if n == left:
buf.write(data)
del data # explicit free
break
assert n <= left, "recv(%d) returned %d bytes" % (left, n)
buf.write(data)
buf_len += n
del data # explicit free
#assert buf_len == buf.tell()
return buf.getvalue()
def readline(self, size=-1):
# pylint:disable=too-many-return-statements
buf = self._rbuf
buf.seek(0, 2) # seek end
if buf.tell() > 0:
# check if we already have it in our buffer
buf.seek(0)
bline = buf.readline(size)
if bline.endswith(b'\n') or len(bline) == size:
self._rbuf = BytesIO()
self._rbuf.write(buf.read())
return bline
del bline
if size < 0: # pylint:disable=too-many-nested-blocks
# Read until \n or EOF, whichever comes first
if self._rbufsize <= 1:
# Speed up unbuffered case
buf.seek(0)
buffers = [buf.read()]
self._rbuf = BytesIO() # reset _rbuf. we consume it via buf.
data = None
recv = self._sock.recv
while True:
try:
while data != b"\n":
data = recv(1)
if not data:
break
buffers.append(data)
except InterruptedError:
# The try..except to catch EINTR was moved outside the
# recv loop to avoid the per byte overhead.
continue
break
return b"".join(buffers)
buf.seek(0, 2) # seek end
self._rbuf = BytesIO() # reset _rbuf. we consume it via buf.
while True:
try:
data = self._sock.recv(self._rbufsize)
except InterruptedError:
continue
if not data:
break
nl = data.find(b'\n')
if nl >= 0:
nl += 1
buf.write(data[:nl])
self._rbuf.write(data[nl:])
del data
break
buf.write(data)
return buf.getvalue()
else:
# Read until size bytes or \n or EOF seen, whichever comes first
buf.seek(0, 2) # seek end
buf_len = buf.tell()
if buf_len >= size:
buf.seek(0)
rv = buf.read(size)
self._rbuf = BytesIO()
self._rbuf.write(buf.read())
return rv
self._rbuf = BytesIO() # reset _rbuf. we consume it via buf.
while True:
try:
data = self._sock.recv(self._rbufsize)
except InterruptedError:
continue
if not data:
break
left = size - buf_len
# did we just receive a newline?
nl = data.find(b'\n', 0, left)
if nl >= 0:
nl += 1
# save the excess data to _rbuf
self._rbuf.write(data[nl:])
if buf_len:
buf.write(data[:nl])
break
else:
# Shortcut. Avoid data copy through buf when returning
# a substring of our first recv().
return data[:nl]
n = len(data)
if n == size and not buf_len:
# Shortcut. Avoid data copy through buf when
# returning exactly all of our first recv().
return data
if n >= left:
buf.write(data[:left])
self._rbuf.write(data[left:])
break
buf.write(data)
buf_len += n
#assert buf_len == buf.tell()
return buf.getvalue()
def readlines(self, sizehint=0):
total = 0
list = []
while True:
line = self.readline()
if not line:
break
list.append(line)
total += len(line)
if sizehint and total >= sizehint:
break
return list
# Iterator protocols
def __iter__(self):
return self
def next(self):
line = self.readline()
if not line:
raise StopIteration
return line
__next__ = next
try:
from gevent.fileobject import FileObjectPosix
except ImportError:
# Manual implementation
_fileobject = _basefileobject
else:
class _fileobject(FileObjectPosix):
# Add the proper drop/reuse support for pypy, and match
# the close=False default in the constructor
def __init__(self, sock, mode='rb', bufsize=-1, close=False):
_do_reuse_or_drop(sock, '_reuse')
self._sock = sock
FileObjectPosix.__init__(self, sock, mode, bufsize, close)
def close(self):
try:
if self._sock:
self.flush()
finally:
s = self._sock
self._sock = None
if s is not None:
if self._close:
FileObjectPosix.close(self)
else:
_do_reuse_or_drop(s, '_drop')
def __del__(self):
try:
self.close()
except: # pylint:disable=bare-except
# close() may fail if __init__ didn't complete
pass
__all__ = __implements__ + __extensions__ + __imports__