You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bytes-like objects with socket.sendall(), SSL, and http.client #71527
According to the documentation, HTTPSConnection.request() should accept arbitrary bytes-like objects, but this is not the case. Currently (since bpo-23756), a “bytes-like object” is defined to be anything that works with Python’s buffer API, as long as it is C-contiguous. These objects can be passed to socket.sendall():
>> byteslike = (ctypes.c_ubyte * 6).from_buffer_copy(b"DATA\r\n")
>> s = socket.create_connection(("localhost", 80))
>> s.sendall(byteslike) # Server receives b"DATA\r\n"
This is not explicitly documented for socket objects. But since bpo-23539 (3.4+), HTTPConnection.request() does document support for bytes-like objects:
>> h = HTTPConnection("localhost", 80)
>> # Send Content-Length: 6 and body b"DATA\r\n"
>> h.request("POST", "/", body=byteslike)
On its own, there is no problem with Python relying on its own undocumented behaviour. But Python’s “ssl” module does not support arbitrary bytes-like objects, and as a result neither does HTTPSConnection:
>>> s = ssl.wrap_socket(socket.create_connection(("localhost", 443)))
>>> s.sendall(byteslike)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/ssl.py", line 886, in sendall
v = self.send(data[count:])
File "/usr/lib/python3.5/ssl.py", line 856, in send
return self._sslobj.write(data)
File "/usr/lib/python3.5/ssl.py", line 581, in write
return self._sslobj.write(data)
TypeError: a bytes-like object is required, not 'list'
>>> c = ssl.create_default_context(cafile="/lib/python3.5/test/keycert.pem")
>>> h = HTTPSConnection("localhost", 443, context=c)
>>> h.request("POST", "/", body=byteslike)
Traceback (most recent call last):
File "/usr/lib/python3.5/http/client.py", line 885, in send
self.sock.sendall(data)
File "/usr/lib/python3.5/ssl.py", line 886, in sendall
v = self.send(data[count:])
File "/usr/lib/python3.5/ssl.py", line 856, in send
return self._sslobj.write(data)
File "/usr/lib/python3.5/ssl.py", line 581, in write
return self._sslobj.write(data)
TypeError: a bytes-like object is required, not 'list'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/http/client.py", line 1083, in request
self._send_request(method, url, body, headers)
File "/usr/lib/python3.5/http/client.py", line 1128, in _send_request
self.endheaders(body)
File "/usr/lib/python3.5/http/client.py", line 1079, in endheaders
self._send_output(message_body)
File "/usr/lib/python3.5/http/client.py", line 913, in _send_output
self.send(message_body)
File "/usr/lib/python3.5/http/client.py", line 892, in send
"or an iterable, got %r" % type(data))
TypeError: data should be a bytes-like object or an iterable, got <class '__main__.c_ubyte_Array_6'>
This could be fixed in the implementation of SSLSocket.sendall(). But I am not sure if that is an appropriate change for 3.5. Another option would be to adjust the documentation of HTTP(S)Connection in 3.5, either not mentioning bytes-like objects at all, or clarifying that they don’t work with SSL.
In Python 3.6 and master, SSLSocket.sendall() now accepts any bytes-like object that can be cast to bytes. Since it uses a sliced memoryview instead of sliced bytes, it avoids extra copies of the payload, too.
Activity
vadmium commentedon Jun 17, 2016
According to the documentation, HTTPSConnection.request() should accept arbitrary bytes-like objects, but this is not the case. Currently (since bpo-23756), a “bytes-like object” is defined to be anything that works with Python’s buffer API, as long as it is C-contiguous. These objects can be passed to socket.sendall():
This is not explicitly documented for socket objects. But since bpo-23539 (3.4+), HTTPConnection.request() does document support for bytes-like objects:
On its own, there is no problem with Python relying on its own undocumented behaviour. But Python’s “ssl” module does not support arbitrary bytes-like objects, and as a result neither does HTTPSConnection:
This could be fixed in the implementation of SSLSocket.sendall(). But I am not sure if that is an appropriate change for 3.5. Another option would be to adjust the documentation of HTTP(S)Connection in 3.5, either not mentioning bytes-like objects at all, or clarifying that they don’t work with SSL.
tiran commentedon Sep 7, 2017
New changeset 888bbdc by Christian Heimes in branch 'master':
bpo-27340: Use memoryview in SSLSocket.sendall() (bpo-3384)
888bbdc
tiran commentedon Sep 7, 2017
New changeset 9423f5d by Christian Heimes in branch '3.6':
[3.6] bpo-27340: Use memoryview in SSLSocket.sendall() (GH-3384) (bpo-3434)
9423f5d
tiran commentedon Sep 8, 2017
In Python 3.6 and master, SSLSocket.sendall() now accepts any bytes-like object that can be cast to bytes. Since it uses a sliced memoryview instead of sliced bytes, it avoids extra copies of the payload, too.