I’m trying to debug an issue where Safari (both on macOS and iOS) fails to load 
an MJPEG stream in some cases. The HTTP response is of content type 
"multipart/x-mixed-replace” and is also using chunked encoding.
The stream works as expected in Firefox and Chrome but fails in Safari. In the 
console I can see the following “errors”:
> [Error] The operation couldn’t be completed. ( error 0.)
> [Error] Cannot load .

A bit more background information (see 
<https://github.com/home-assistant/home-assistant/issues/13995>): the HTTP 
response is an MJPEG stream created by a project called “Home Assistant”, in 
addition the response is proxied by an nginx server. When pointing Safari to 
the stream directly, not via the proxy, it works. I’ve also tested this with 
another server (https://github.com/jacksonliam/mjpg-streamer 
<https://github.com/jacksonliam/mjpg-streamer>) proxied by the same nginx 
server which does work as expected but I’ve yet to find any crucial difference 
between the two responses that would make it not work.
Here’e an example of the server response:
> HTTP/1.1 200 OK
> Server: nginx/1.10.3
> Date: Tue, 09 Apr 2019 14:59:54 GMT
> Content-Type: multipart/x-mixed-replace; boundary=--frameboundary
> Transfer-Encoding: chunked
> Connection: keep-alive
> Strict-Transport-Security: max-age=31536000; includeSubdomains
> Cache-Control: private
> Cache-Control: no-cache
> Cache-Control: no-store

Looking at the network dump, I can see the packets are all accepted until the 
second frame/boundary is received and is then reset by the client. The 
content-length header seems correct.
I’m thinking maybe Safari/WebKit doesn’t parse this connection correctly or 
there is some quirk in the response so I figured that if I can find why the 
connection is cancelled on WebKit’s side, I could understand the root cause.

I went ahead and compiled WebKit and tried to understand the flow of things but 
it’s taking me quite some time so perhaps anyone here could point me in the 
right direction.

So far, the lowest point I reached was a call to 
WebResourceLoader::didReceiveResponse() with has a status of 200 and 
needsContinueDidReceiveResponseMessage is false. After this the request is 
canceled (it reaches ResourceLoader::cancel() with a null error, i.e 
error.isNull() is true).

Can anyone please point me to where in the code chunked and/or multipart 
responses are parsed with the default configuration (not using curl, etc.) so 
that I might understand why it rejects the stream?

Thanks in advance!

Attachment: smime.p7s
Description: S/MIME cryptographic signature

webkit-dev mailing list

Reply via email to