So I have a "work-around" (aka a really horrible cruft!)
The first observation is that someone put the assert in the read()
function "__init__.py" to detect precisely this problematic condition
- that the recv( 8192) call returns more than 8192... And yes, under
certain conditions, under ssl, it clearly does (but maybe not for
everybody!)
I put stack trace into the recv function and tested uploading a 10k
file, and it is clear that when read() calls self.recv(8192), the call
initially visits a recv() fn in the ssl library, which then calls down
to the __init__ recv() function *twice*, first getting 8192 bytes,
then getting a further 2k, all of which (10k) it then returns to the
read function.
So it seems to be the ssl library that isn't honouring the (8192)
constraint.
So, as I don't at all understand the overall design of this stack, in
the best tradition of modern medicine, my "cure" is to treat the
symptoms (duh!)...
In the read() routine (around line 900 in __init__.py) in the event
there is more than the requested data, instead of running straight
into the assert, I write out the requested amount (typically 8192),
and stash the rest away in a variable "self._datastash", which I
create on the fly (I said it was nasty!) On entering read(), before
fetching any new data, I check if there is anything in
self._datastash, and if so, I return it....
I'm sure that if I came understand exactly how the buffers in that
routine are properly being used, I could forge a more elegant
solution, but my head hurts too much already...
<snip somewhere_around_line=900, comments=mostly_removed>
if size < 0:
self._rbuf = StringIO.StringIO() # reset _rbuf. we
consume it via buf.
while True:
### start fixup
try:
if self._datastash:
data = self._datastash
self._datastash = ''
else:
data = self.recv(rbufsize)
except:
self._datastash = ''
### end fixup (plus indented next line)
data = self.recv(rbufsize)
if not data:
break
buf.write(data)
return buf.getvalue()
else:
<snippy />
while True:
left = size - buf_len
### start fixup
try:
if self._datastash:
data = self._datastash
self._datastash = ''
else:
data = self.recv( left)
except:
self._datastash = ''
### end fixup (plus indented next line)
data = self.recv( left)
if not data:
break
n = len(data)
if n == size and not buf_len:
return data
if n == left:
buf.write(data)
del data # explicit free
break
### start fixup
if n > left:
buf.write(data[ :left])
self._datastash = data[ left:]
del data # explicit free
break
### end fixup
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()
</snip>
I hope this is useful to someone, with luck, to sort it out properly
(somehow) for the next release...
Thanks, Alan