Schnouki/spop

dspop: Read from socket is prematurely terminated

Closed this issue · 1 comments

The code

buf = b""
while True:
    tmp = self._sock.recv(128)
    buf += tmp
    if len(tmp) < 128:
        try:
            obj = json.loads(buf.decode())
            return obj
        except:
            continue

may terminates before the complete JSON data is received. UTF-8 characters has varying byte length, up to 4, so the server may not be able to send everything in 128 bytes chunks.

A message protocol is needed to avoid the problem, a bigger buffer will lessen the likelihood of occurring.

I was unable to search for metallica before increasing the buffer to 1024.

Thanks for this detailed bug report! I was able to reproduce the issue when searching for metallica, but I don't think it's related to UTF-8.

When searching for metallica, dspop ends up issuing a uinfo "spotify:album:6UMU8LcfAJQln8TdPizezi" command. When reading the result, the last call to self._sock.recv(128) returns exactly 128 bytes. And because of that, there's no attempt to decode the JSON buffer, and dspop stays stuck at the next recv call.

So simply removing the if len(tmp) < 128 line fixes this issue, without needing to change the buffer size. (It even works when setting the buffer size to 1, which IMHO proves that this is not related to UTF-8).
However, this causes some overhead as there are more attempts to decode an incomplete JSON object (even more visible when setting the buffer size to 1 ;)). So I also changed the buffer size to 1024.

I fully agree that a message protocol would avoid this problem. I'll probably do that in the future.