Reputation: 21
I am not sure if this is a programming question or a web server config question.
The video files are not in public/
so requests have to go through a controller.
In my controller:
def play_video
video=Video.find params[:id]
response.headers['Content-Length'] = File.size(video.path).to_s
send_data File.read(video.path,mode: 'rb'), type: video.mime_type, disposition: 'inline'
end
On the client-side I am using JPlayer
for now.In Firefox running on Linux in both development and production it works properly, I can jump forward or backward without issue. In just about every other browser on Linux and Windows, it plays properly, but that is it, no skipping forward or backwards, in development and production. I would put it up to a JPlayer
bug but I get the exact same behavior with using just <video> with control attribute
, as well as mediaelement.js
.
In development I am using Thin
, on production Passenger
and Nginx
.
nginx.conf:
worker_processes 4;
events {
worker_connections 1024;
}
sendfile on;
#tcp_nopush on;
http {
passenger_root /usr/local/lib64/ruby/gems/2.2.0/gems/passenger-5.0.11;
passenger_ruby /usr/local/bin/ruby;
keepalive_timeout 120;
gzip on;
server {
server_tokens off;
listen 80 default_server;
listen 443 ssl;
server_name www.example.com;
root /path/to/public;
passenger_enabled on;
client_max_body_size 100M;
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
include mime.types;
default_type application/octet-stream;
#removed SSL config stuff
...
I am not sure where the problem lies. I get no error messages when trying to skip forward.
Please don't link to Rails HTTP Streaming tutorials as they are all lame and not-at-all-helpful send "hello world" to the client 10 times examples, unless you have one that actually addresses video streaming. Anything I did find were for old versions of rails and other web servers.
Upvotes: 1
Views: 796
Reputation: 15530
This is an anti pattern what you are trying to do, send_file is fully blocking synchronical mechanism, basically it requires N number of Rails processes as many requests as your app will serve at a time. It is being done by a reason to have controlled access to file or perform any kind of pre/post processing: permission check, audit etc.
If this is the anti pattern how the pattern looks like: 1) X-Accel-Redirect 2) Async permission check via auth_request module
In the first case your Rails app returns back only the file's URL within the X-Accel-Redirect header with empty body followed by closing this request so Rails can continue serving a new request again immediately not waiting until a client gets the file (in case of slow client's connection Rails can't free process up until it finished). Basically to serve 10 large video files simultaneously 10 workers require you to have. X-Accel-Redirect makes same job with only one worker:
Rails
def download
video=Video.find params[:id]
headers['X-Accel-Redirect'] = "#{video.file_name}"
render nothing: true
end
Nginx
location /video {
internal;
root /mnt/video;
}
The alternative is auth_request which is similar by efficiency but you need to know file target URL beforehand not generate by server. Auth_request location is internal and it handles authentication by Rails route followed by rejection or pass user to target video file URL:
Nginx
location /video/ {
root /mnt/video;
auth_request /auth;
...
}
location = /auth {
internal;
proxy_pass http://localhost;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
Upvotes: 2