self._write_buffer_pos = 0
self._write_buffer_size = 0
self._write_buffer_frozen = False
+ self._pending_writes_while_frozen = []
self._read_delimiter = None
self._read_regex = None
self._read_max_bytes = None
if (self.max_write_buffer_size is not None and
self._write_buffer_size + len(data) > self.max_write_buffer_size):
raise StreamBufferFullError("Reached maximum write buffer size")
- self._write_buffer += data
- self._write_buffer_size += len(data)
+ if self._write_buffer_frozen:
+ self._pending_writes_while_frozen.append(data)
+ else:
+ self._write_buffer += data
+ self._write_buffer_size += len(data)
if callback is not None:
self._write_callback = stack_context.wrap(callback)
future = None
"delimiter %r not found within %d bytes" % (
delimiter, self._read_max_bytes))
+ def _freeze_write_buffer(self, size):
+ self._write_buffer_frozen = size
+
+ def _unfreeze_write_buffer(self):
+ self._write_buffer_frozen = False
+ self._write_buffer += b''.join(self._pending_writes_while_frozen)
+ self._write_buffer_size += sum(map(len, self._pending_writes_while_frozen))
+ self._pending_writes_while_frozen[:] = []
+
+ def _got_empty_write(self, size):
+ pass
+
def _handle_write(self):
while self._write_buffer_size:
+ assert self._write_buffer_size >= 0
try:
start = self._write_buffer_pos
if self._write_buffer_frozen:
size = self._write_buffer_size
num_bytes = self.write_to_fd(
memoryview(self._write_buffer)[start:start + size])
- assert self._write_buffer_size >= 0
if num_bytes == 0:
- # With OpenSSL, if we couldn't write the entire buffer,
- # the very same string object must be used on the
- # next call to send. Therefore we suppress
- # merging the write buffer after an incomplete send.
- # A cleaner solution would be to set
- # SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER, but this is
- # not yet accessible from python
- # (http://bugs.python.org/issue8240)
- self._write_buffer_frozen = size
+ self._got_empty_write(size)
break
- self._write_buffer_frozen = False
self._write_buffer_pos += num_bytes
self._write_buffer_size -= num_bytes
# Amortized O(1) shrink
if self._write_buffer_pos > self._write_buffer_size:
del self._write_buffer[:self._write_buffer_pos]
self._write_buffer_pos = 0
+ if self._write_buffer_frozen:
+ self._unfreeze_write_buffer()
except (socket.error, IOError, OSError) as e:
if e.args[0] in _ERRNO_WOULDBLOCK:
- self._write_buffer_frozen = size
+ self._got_empty_write(size)
break
else:
if not self._is_connreset(e):
def writing(self):
return self._handshake_writing or super(SSLIOStream, self).writing()
+ def _got_empty_write(self, size):
+ # With OpenSSL, if we couldn't write the entire buffer,
+ # the very same string object must be used on the
+ # next call to send. Therefore we suppress
+ # merging the write buffer after an incomplete send.
+ # A cleaner solution would be to set
+ # SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER, but this is
+ # not yet accessible from python
+ # (http://bugs.python.org/issue8240)
+ self._freeze_write_buffer(size)
+
def _do_ssl_handshake(self):
# Based on code from test_ssl.py in the python stdlib
try: