sabnzbd / sabnzbd

SABnzbd - The automated Usenet download tool

Home Page:http://sabnzbd.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Invalid handling of chunked delivery of status codes

Safihre opened this issue · comments

SABnzbd version

Any

Operating system

Any

Using Docker image

None

Description

User reported Downloader crashes:
https://forums.sabnzbd.org/viewtopic.php?t=26559

First we expected just a crappy server since it's not one of the very well known providers, but the user supplied us with a test NZB and access to the server.

I found that our status code handling in recv_chunk and process_nw does not consider that statuses can be delivered in chunks.

As an example for pre-check:

  1. We request the article.
  2. First recv_chunk the data received and in the buffer is 223 0 <8ovy7qDr2UbhGvy6Xo6@107f9dd2724620839a39cFeqL0UPPpJjg1sd0, which is missing the closing >\r\n
  3. We see the 223 in process_nw and say Article present.
  4. We request the next article and reset the nw.data_position to 0, however, the server wasn't done yet with our first request.
  5. The next recv_chunk we read the leftover >\r\n and now nw.data[:nw.data_position] is: >\r\n

NNTP always ends in \r\n, so we should not have done anything unless that was the last data we recieved.

Awesome edge case!

How are you intending on resolving it?

I was thinking we could make nw.status_code search for \r\n and handle it returing None in process_nw also cache/store the value to avoid repeatedly searching.

I think you should use data_view for the search, else you'd copy the whole buffer.
I recall from the spec there is a maximum line length you could limit it to but slicing the data_view doesn't use memory anyway.

commented

I recall from the spec there is a maximum line length you could limit it to

That would be RFC 3977 §3.1: The initial line of the response MUST NOT exceed 512 octets, which includes the response code and the terminating CRLF pair [...]

I think it's pretty simple, we need to modify recv_chunk to also return if it's end of line CRLF.
Only if that's the case we process the status code.