[webkit-dev] A Little Help Debugging Chuked + multipart/x-mixed-replace Responses

Assaf Inbal shmuelzon at gmail.com
Fri Apr 12 05:51:09 PDT 2019


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 <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!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-dev/attachments/20190412/8b69897c/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 1933 bytes
Desc: not available
URL: <http://lists.webkit.org/pipermail/webkit-dev/attachments/20190412/8b69897c/attachment.bin>

More information about the webkit-dev mailing list