New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Express server doesn't support content-range for serving local video/media files #8888
Comments
Would definitely love help pushing this one forward... |
I did a little bit of poking around, seems like we need to tweak the logic here: To be more like: lastModified = stat.mtime.toUTCString();
response.setHeader('Last-Modified', lastModified);
// nginx style treat last-modified as a tag since browsers echo it back
if (request.headers['if-modified-since'] === lastModified && !request.headers.range) {
response.writeHead(304);
response.end();
return;
}
const mimeType = mime.contentType(path.extname(filename));
// read file sync so we don't hold open the file creating a race with
// the builder (Windows does not allow us to delete while the file is open).
buffer = fs.readFileSync(filename);
if (request.headers.range) {
const range = request.headers.range;
const total = content.length;
const [partialstart, partialend] = range.replace(/bytes=/, "").split("-");
const start = parseInt(partialstart, 10);
const end = partialend ? parseInt(partialend, 10) : total;
const chunksize = end - start;
response.setHeader('Content-Range', `bytes ${start}-${end}/${total}`);
response.setHeader('Accept-Ranges', 'bytes');
response.setHeader('Content-Length', chunksize);
response.setHeader('Content-Type', mimeType);
response.writeHead(206);
response.end(buffer.slice(start, end));
return;
} else {
response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate');
response.setHeader('Content-Length', stat.size);
response.setHeader('Content-Type', mimeType);
response.writeHead(200);
response.end(buffer);
} |
Looks good to me @rwjblue. Has all the headers I believe we need, particularly:
I just made a series of test to help with this, they compare the responses of video hosted on a CDN (what we should be getting back) vs one in the local assets (failing). It includes a video file for testing too. I did it on both the Unit level, just checking the headers of the response, and also an integration test where a video element is rendered on the page and test whether seeking in Chrome works. |
I am trying to play a local video (public folder) on Safari and it is not working. Could this be why? |
@tavosansal : Yes, this is likely where your problem is coming from. Safari is more strict about how it handles server responses to Range requests than Chrome. In my experience, if the server incorrectly replies (which Express tends to do by default), Safari will generally treat it as an unreadable media. |
😸 |
Yeah. I went down a rabbit hole with Safari yesterday and found a browser bug. Reported it to Apple with a demo video, but haven't yet (and don't really expect to) heard anything back. I haven't yet wrapped my head around why Broccoli is managing a middleware for Express. And even when it does, why it's not somehow delegating to Express's serve-static. That middleware already supports all of the behaviors we need. The complication is that it's expecting to point to static directories for the static files, where Broccoli is dealing with dynamically created and changing directories (I assume). |
@nbibler we are seeing similar issues with not using serve-static for our application use case. We are investigating how to remove the middleware in broccoli to utilize serve-static. |
I wonder if it would make more sense to use serve-static in https://github.com/ember-cli/broccoli-middleware/blob/master/lib/serve-asset-middleware.js and replace the custom serve code. |
TLDR;
Cannot seek playback time of a video file served from localhost during Tests because ember-cli's express server configuration doesn't support
Content-Range
and serves the file with a 200 response instead of 206 partial content.Details:
This is a known issue for how Chrome handles video content. Chrome makes multiple HTTP request with Range header for media file and expects HTTP Content-Range and Content-Length response header with 206 Partial Content status. If server send '200 OK' status Chrome will not play the media file. If server send '200 OK' status with response header 'Accept-Ranges: none' then Chrome will play media file, but seeking/jumping to a specific time will not work.
Reproduce:
Insert a video into your template and look at the status code. If the video is served locally it will have a 200 response and seeking playback to a specific time will not work, if it is served externally from a CDN it will have a 206 response and seeking playback works.
Recommendations:
A) Instead of an Express server, we use
http-server
which support partial content.B) Add support for serving partial-content (see gist below)
Resources:
https://gist.github.com/padenot/1324734 (How to serve media on node.js)
https://medium.com/better-programming/video-stream-with-node-js-and-html5-320b3191a6b6
Output from
ember version --verbose && npm --version && yarn --version
:The text was updated successfully, but these errors were encountered: