Fix logic for non-keepalive connections#222
Fix logic for non-keepalive connections#222mherger merged 2 commits intoLMS-Community:public/7.9from
Conversation
|
@philippe44 - what do you think about this patch? As you did the previous change in there, I was wondering whether this would conflict with your approach. |
There was a problem hiding this comment.
Yep ... I don't know what I was thinking of at that time. What I really wanted was to avoid the problem where, in a persistent connection, the whole body is already buffered when handling the headers. In that case, there will be no socket event generated and the body will be missed.
So the right test is "when the full body has been received and there is no connection header or the connection header is keep-alive, then call _http_read_body".
_http_read_body( $self->socket, $self, $args ) if ( (!$self->response->headers->header('Connection') || $self->response->headers->header('Connection') =~ /keep-alive/i ) && $self->socket->_rbuf_length == ($headers->content_length || 0) );
I also don't know why I was using $headers and $self->reponse->header, as I think they are the same. Using $headers is shorter but less clean as the $headers variable should probably not be considered valid at that time as some later code modification might change it between the moment it is used to populate $self->reponse and this test
|
I'll update my change with that and give it a try. Thanks everyone for taking a look. |
|
I tried the new test and it exhibited the same problem. After further though I think the right test is simply to check for "keep-alive" (see new commit). The reason is that HTTP/1.0 defaults to non-keep-alive, and only if the response contains a keep-alive "Connection" header is it actually a persistent connection. Checking for an empty/missing "Connection" header would only make sense for HTTP/1.1 since the default is keep-alive. Here's the debug log for one of the podcasts that was giving trouble. Note our request is HTTP/1.0 and that the response has no "Connection" header or "Content-Length". In this case we should treat it as non-keep-alive, but the revised test would treat it as keep-alive and force a premature zero byte read. [18-11-01 21:23:17.0523] Slim::Networking::SimpleAsyncHTTP::_createHTTPRequest (110) GETing http://feeds.feedburner.com/thornmorris ] |
|
I'm wondering then if we should not do a more complete test. An HTTP 1.1 connection w/o a Connection header should be considered persistent and in that case the current patch would break that, the same way my other proposal broke the HTTP 1.0
|
|
Unless I'm misunderstanding the code the request will always be HTTP/1.0, there are several places in the module where the protocol is explicitly set to HTTP1.0. The comments state that HTTP/1.1 is not supported because there is no code to handle chunked encoding (which are always permitted in 1.1). |
|
Then you're right, I did not read enough the code. It took me a while to remember where I needed that. This is for ATV pairing, where the HTTP connection must be kept alive |
|
Thanks @philippe44. |
|
Thanks to you - I feel bad I injected some crap in LMS' code :-( |
|
Thanks for the constructive discussion. I learned a bit about our code 😀. We’re all good to merge this then? |
|
Yup. |
|
Thanks a lot, both of you! |
|
BTW, I found what was my original intention and why I thought it was working. It's for my AirPlay bridge: the pin-pairing negociation with ATV requires the session to be persistent, but when receiving an HTTP 1.0 with a "Connection:keep-alive", the ATV responds with no "Connection" header, so I needed that to be considered as a a valid keep-alive session. |
|
Makes sense. I've been wondering if the whole thing couldn't be simplified to simply call _http_read_body if _rbuf_length > 0. That should work for every case, without needing to determine if we are in a keep-alive situation or not. In fact I think this (or something like it) should be built-in to the Select logic automatically, rather than needing the caller to figure it out. |
|
I agree but these changes are scary as they can have lots of side effect and validation capabilities of LMS are thin (...) |
This fixes a problem that occurs on non-keepalive HTTP connections under certain timing conditions. The logic around deciding if a connection is keepalive is reversed in the case that the fix deals with. Because of this, the code will sometimes call _http_read_body with a zero length body on non-keepalive connections. A zero length read within _http_read_body is treated as end of data and the connection gets closed.
Since it is timing dependent, I've only noticed this on certain podcasts and not every time. Sometimes retrying the podcast will make it work. I've also noticed that with logging enabled it sometimes does not repo. Here's some podcasts I've noticed the problem:
http://sleepwithmepodcast.libsyn.com/rss
http://feeds.feedburner.com/thornmorris