Closed vquie closed 5 years ago
Tried it with different browsers. Does NOT work on:
Does work on:
I'm seeing this issue as well, it appears to be a caching issue with Apple-based browsers, including the SafariControllerView.
I'm finding that if I reload the page with an empty cache (Shift-Click the reload icon in macOS Safari), or force quit iOS Safari or the Home Assistant app, the camera stream will load. Then refreshing the page without emptying the cache causes the issue to resurface.
To add specifics; I'm serving HA behind a reverse-proxied instance of macOS Server's apache2 server with SSL.
@jamieshaw Thank you very much. Looks like it is working in the iOS app as well. Don't know how I tested it that it did not work.
Not sure if it's worth keeping this issue open as it may be an issue with how Home Assistant is rendered in Safari; and not necessarily a greater bug in Apple's browsers.
Until further investigation to rule out a bug in Safari's behaviour, I'd recommend leaving open.
I've got the same problem with HA 0.68.1 running behind an nginx proxy. No mjpeg stream to Safari on iOS or MacOS.
Same problem here works with Chrome and Firefox not Safari ..
MacOS Home Assistant 0.69.1 Apache Reverse Proxy (homebrew) One FFMPEG camera playing an MP4 file One FFMPED camera playing an RSTP camera stream 4 Static image JPG cameras Chrome, Firefox, Safari, iOS app
Noticed the behavior after upgrading from .67 to .69.1. I'm seeing 200 success messages when starting the stream in the server logs and no errors in homeassistant.components.http.view or haffmpeg.core debug logs. The video stream is alive and will display through homekit. It displays a broken image icon, no errors in the web console other than the 4040 about the entity registry which another bug report says is normal.
Video Thumbnails: Display in all browsers MP4 Stream: Displays only in Chrome RTSP Stream: Doesn't display in any browser Static JPG: Display full-size window in chrome and Firefox
Found two possible causes. Depending on the type of camera, you might be hitting the max allowed connections. The Foscams I have are limited to 4 streams. Which brings me to the semi-workaround, I've disabled KeepAlive on my httpd proxy. The call api/camera_proxy_stream/camera.whatever sends a KeepAlive in the header, if you hit HA directly, the python webserver doesn't respond with KeepAlive while Apache httpd does. There are still times when the image doesn't load (still limited to 4 streams), but it's far less frequent.
Just upgraded to home-assistant 0.73. The stream ist working now through safari. Can anyone else confirm?
I have a similar problem with uvc (UniFi Camera NVR) and haproxy (SSL). The live stream shows just fine when I directly to home-assistant's local IP and port 8123, but not when going through haproxy.
Edit: Sorry, forgot to mention: works with chrome, doesn't work with safari. Edit2: Shift-Click reload temporarily fixes the issue on Safari.
I am affected too when using Safari with HA 0.79.3, with Chrome it works fine. When using Safari directly (http://192.168.0.10:8123) without proxy it works even with Safari.
Found something on https://www.home-assistant.io/docs/ecosystem/apache/ that seems to have helped out a bit. Specifically disablereuse=on
being set for the proxy. I just enabled that and so far it's been way more reliable loading the stream. I'm still limited by my cameras ability to only have 4 streams at once, but this is far better than before.
any news to this? who could help us? whats needed to help us?
There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates.
Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment :+1:
nope still the same problem with latest release :(
I have the same issue. Fails in Safari, but works in Chrome. There is an error in the console, but no stacktrace nor reference to anything actually.
[Error] The operation couldn’t be completed. ( error 0.)
[Error] Cannot load .
For what it's worth, here's what I found so far: Just as @tkislan, I saw the same errors in safari. Using Wireshark, I can see that Safari closes the connection with a TLS/SSL alert "Level: Warning, Description: Close Notify". The HTTP request is pretty much the same between an SSL connection (proxied by nginx) and a direct HTTP request to HA:
GET /api/camera_proxy_stream/camera.generic_camera?token=<token> HTTP/1.1
Host: raspberrypi.local:8123
Connection: keep-alive
Accept: image/png,image/svg+xml,image/*;q=0.8,video/*;q=0.8,*/*;q=0.5
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15
Accept-Language: en-us
Referer: http://raspberrypi.local:8123/lovelace/default_view
Accept-Encoding: gzip, deflate
The server response is a bit different as the server name is different and some cache-control headers are included. HTTP:
HTTP/1.1 200 OK
Content-Type: multipart/x-mixed-replace; boundary=--frameboundary
Transfer-Encoding: chunked
Date: Tue, 09 Apr 2019 14:31:19 GMT
Server: Python/3.5 aiohttp/3.5.4
HTTPS:
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
Another thing that might be worth mentioning is that the initial chunk when using SSL is smaller and does not include the entire MJPEG frame:
ffa
--frameboundary
Content-Type: image/jpeg
Content-Length: 14893
As opposed to the HTTP variant:
48c6
--frameboundary
Content-Type: image/jpeg
Content-Length: 18560
The latter include the entire frame boundary and the frame itself (as expected). Maybe Safari can't handle the MJPEG frame being split to multiple HTTP chunks?
Anyways, the requests and responses are the same for both Safari and Chrome so it's "just" a matter of Safari not handling it correctly.
Edit: I also compared the network dump on the proxy server and can confirm nginx is manipulating the HTTP chunks and seems to be limiting them to 0x1000 (4096) bytes.
Edit 2: it seems the MJPEG streams don’t really need to be chunk-encoded. I’ll try to see if I can remove that and if it makes any difference.
After trying out a few things, I don't think it's directly related to the chunked encoding. Using mjpg-streamer as the server with the same nginx proxy works as expected. I did notice that HA sends the boundary incorrectly in the header:
Content-Type: multipart/x-mixed-replace; boundary=--frameboundary
When it should be without the two dashes, i.e.:
Content-Type: multipart/x-mixed-replace; boundary=frameboundary
Fixing this does cause Safari to accept the first JPEG frame, but when the second one starts it resets the connection again. Not sure yet if it's something to do with HTTP chunks or the second multipart, but it's a start...
this is really annoying, still having that issue :(
Sadly, I was never able to get to the root cause of the issue. It’s not directly related to SSL nor chunked encoding as I have another working example. I tried producing the same responses from mjpg-streamer in HA (same headers, same chunk sizes, etc.) but that didn’t work. The only difference remaining was the JPEG frame itself. I was able to reach the point that Safari read the first complete frame but then it rejected it for some reason. Webkit’s code is quite complex and I couldn’t fine the actual location where the decision that the HTTP content isn’t an image was made, only caught it somewhere down the line...
So I've just had another look into this, as it's one of the bugs still in my config.
I'm wondering if it's just Safari's poor service worker support in version 12? The latest technology preview doesn't appear to have an issue…
Hi @jamieshaw, I just tested it with the latest Tech Preview too... but I have exact the same issue. It is still only working with Chrome or Firefox, not with Safari. :(
It’s been a while but, IIRC, after fixing the HTTP boundary, Webkit didn’t recognize the first frame as an image and closed the connection. The only lead I have right now is the fact that the working example is an EXIF image while the non-working one is a JFIF. I don’t know if it’s related but I wanted to try and re-encode the frame in HA to see if that makes any difference but I never got around to trying. @jamieshaw, @nicx, could you please check the JPEG format of your cameras and tell me which JPEG type it is? Looking at the first few bytes of the image should be enough. Maybe that could tell us if it’s related or not...
@shmuelzon am using Hikvision cams, they are using JFIF type.
There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue now has been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.
I'm seeing this exact same issue with home assistant 0.104 and https enabled. Only in safari, chrome, firefox Fully, IOS app and Kiosk browser working fine.
Anybody managed to get this solved, or having further hits/pointers on where to look? Even going through Nabu Casa remote access, this fails in safari. (we might raise it there, for them to try an figure this out, and then see what solution they come up with :) )
I've been digging through disabling buffers, keep-alive, etc in nginx, but no avail just yet.
Ofcourse it works when accessing HA directly, without going through nginx.
Last time I investigated this there were two issues. The first was the HA didn't correctly create the multipart HTTP content as described here. After fixing that I tried to debug Safari/WebKit and it seemed that the combination of chunked encoding (which the NGINX proxy adds) and the JFIF format caused WebKit to fail detecting the chunk as an image and then it closes the connection. As a workaround, it may be possible, in HA, to remux the JPEG frame and convert it from the JFIF format to the EXIF format. I think the only difference is the header of the file and the image itself is the same. I may be enough to just pass the image through the PIL library but I never got around to try this.
Tnx for the quick response!
I managed to get some progress in macOS safari: I created another nginx server definition without ssl on the same domain and a different port, and that just worked.
Even weirder, it also caused the ssl site definition to work, but it's a bit erratic. When copying the url of the stream (.../api/camera_proxy_stream/...
) into an incognito window, it would break, but later work. It now even keeps working if I remove website data for that domain, restart the browser and try the url again.
The behaviour on mobile (safari, chrome, firefox) is a bit different: It works for http, but consistently doesn't work for https nginx server definition
Yes, that's what I saw as well. My guess is that with the SSL encapsulation WebKit get's a smaller buffer from the mjpeg frame and just fails parsing it. I never was able to find the root cause of it thought. I tried posting on the WebKit mailing list but no one responded. As I don't think it will be fixed there anytime soon and, even if it will, it would take a while until it makes its way to the next stable version, we might need our own workaround here. I have a different device that publishes an mjpeg video also behind an NGINX proxy that works just fine with Safari. The only difference I could find was the jpeg format I mentioned before. That's why I suggest trying to convert each frame in HA when streaming to see if it makes a difference.
I've worked around it by switching from PWA to the IOS companion app, there it does work. I did have to sacrifice my client-certificates authentication for something else through, as that's not supported in the ios app. Anyhow, I've worked around it sadly instead of solving it.
Thanks for all the pointers! I've got a fairly well working situation now.
@mkarnebeek
I created another nginx server definition without ssl on the same domain and a different port, and that just worked.
Can you elaborate on that a little bit? I'd love to try this fix out.
I currently have something along the lines of:
server {
listen 12345 ssl;
server_name my.domain.name;
ssl_certificate /etc/nginx/extra/my.domain.name/crt;
ssl_certificate_key /etc/nginx/extra/my.domain/name/key;
include /etc/nginx/extra/options-ssl-nginx.conf;
ssl_dhparam /etc/nginx/extra/ssl-dhparams.pem;
location / {
proxy_pass "http://homeassistant.local:8123";
proxy_set_header Host $host:$server_port;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto "https";
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_set_header Sec-WebSocket-Protocol $http_sec_websocket_protocol;
proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key;
proxy_set_header Sec-WebSocket-Extensions $http_sec_websocket_extensions;
proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version;
}
}
Where options-ssl-nginx.conf contains:
# https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/options-ssl-nginx.conf
ssl_session_cache shared:le_nginx_SSL:1m;
ssl_session_timeout 1440m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
I added another definition without all of the ssl stuff, on a different port number:
server {
listen 12346;
server_name my.domain.name;
location / {
proxy_pass "http://homeassistant.local:8123";
proxy_set_header Host $host:$server_port;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto "http";
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_set_header Sec-WebSocket-Protocol $http_sec_websocket_protocol;
proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key;
proxy_set_header Sec-WebSocket-Extensions $http_sec_websocket_extensions;
proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version;
}
}
And pointed macOS Safari to http://my.domain.name:12346, logged into HA, and my videostream appeared. After pointing Safari again at https://my.domain.name:12345, the stream magically also appeared, where it previously didn't. Trying it again this morning, it didn't work on https anymore. The behaviour on https seems erratic, on http is seems stable enough for general use, but it wouldn't surprise me that a different bitrate/resolution/whatever would cause it to break again.
For some reason the iOS companion app doesn't suffer from this, where all other browsers on iOS (chrome, firefox tested) do suffer from it.
Also: the stream is only broken when passing through a proxy (Nabu Casa included). When accessing it directly using homeassistant.local
for example, it always works.
I think @shmuelzon is on the correct path: Trying a different JPEG format sent by HA would change things, or ofcourse, solving it in WebKit.
Ah, ok. I wonder why this issue doesn't seem to get any traction from the HA team to help review. It's a very old issue at this point.
Well, first of all, this issue is closed. Second, I guess the people using an SSL proxy in front of HA are a minority. Add to this the fact that the problem isn't in HA to begin with. I guess it's just not interesting enough...
True, but it does affect Nabu Casa as well, which is a paid service.
That's a good point. Personal SSL proxies are out of scope for HA but Nabu Casa is a different story. I don't personally use it but perhaps it would be best to open a new issue stating the problem while using Nabu Casa and referring to this ticket for technical details.
I see the same issue in Safari over https via Cloudflare Tunnel. Safari local and via Tunnel over HTTP work fine.
Any news on this? I still have no Videos in Safari and I do not use any proxies, but have the SSL directly in the HassOS VM.
Was someone able to fix this?
Hey, I think that, as this is technically a bug in WebKit's implementation, Home-Assistant isn't inclined to handle it but, as @mbaran5 mentioned, it also doesn't work through the paid Nabu Casa service so perhaps someone using that service can open a bug for that platform and reference here for technical details.
From what I have so far, there several issues here:
--frameboundary
should be frameboundary
. Fixing this only caused the first frame to work on Safari but the following ones did notAs an example, if I try to access the mjpeg-streamer directly, not via HA, behind the SSL proxy, Safari can display the stream just fine, when it's proxied via HA, it doesn't work. The below screenshot has the stream as provided directly by mjpeg-streamer on the left and the HA-proxied version on the right. The left one is works with an SSL proxy but the right one does not:
Any news on this? I wonder why this is broken so long while it also affects the paid subscription service. Even if it's a WebKit problem there seems to be a possible solution pointed out.
I would not care when the App would allow easier switch between multiple homes but like that it's a p.i.t.a.
Been having this issue as well. Initially thought it was just some weird error in my configuration/cameras but then happened to access HA with a non-safari browser and to my surprise the Glance-cards worked just fine.
Really weird that an issue affecting the whole Apple ecosystem, the official iOS/iPadOS app and even paid subscription is not being taken care of after all these years.
@hiatsu0 It's a bug in WebKit (the web browser engine) Apple use so it affects all of their devices. The bug relates somehow to parsing a specific type of JPEG type, JFIF vs EXIF, when it comes in chunks (which is, usually, what happens when using a proxy. It would be ideal to fix it in WebKit (and wait for it to arrive in the relevant Apple OS versions). Alternatively, a work-around might be for HA to transcode the JPEG images from one format to another.
Home Assistant release with the issue: 0.67.1
Last working Home Assistant release (if known): Tried with 0.66 before, same issue
Operating environment (Hass.io/Docker/Windows/etc.): Raspbian 9.1 - virtualenv
Component/platform: https://www.home-assistant.io/components/camera.mjpeg/ https://www.home-assistant.io/docs/ecosystem/apache/
Description of problem: When serving through apache2 proxy with ssl enabled vhost, there is no camera stream available.
Problem-relevant
configuration.yaml
entries and (fill out even if it seems unimportant):Traceback (if applicable): hass log:
apache2 log:
Additional information: Browser reports: