0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

nginx-lua-moduleでHTTPのRange Requestsを実装する

Last updated at Posted at 2017-02-10

ローカルで運用しているnginxサーバー上のmp4ファイルをchrome経由で閲覧したときに、
シークができなかったので、HTTPのRange Requestsをluaで実装した。

ローカルでの運用を考えているため、セキュリティ対策など考えられていません。
流用の際は十分ご注意ください。
記事内のsample.comは各自の環境に置き換えてください。

環境

インストール

$ sudo apt-get install nginx nginx-extras
$ dpkg -l | grep nginx
ii  nginx                              1.10.0-0ubuntu0.16.04.4                   all          small, powerful, scalable web/proxy server
ii  nginx-common                       1.10.0-0ubuntu0.16.04.4                   all          small, powerful, scalable web/proxy server - common files
ii  nginx-extras                       1.10.0-0ubuntu0.16.04.4                   amd64        nginx web/proxy server (extended version)

nginx-lua-moduleの動作確認

まずは、helloコマンドを実装。

nginxのsite設定

$ sudo vim /etc/nginx/sites-available/dl.sample.com

server {
  listen  443 ssl;
  server_name dl.sample.com;
  location / {
    root  /var/www/html;
  }

  location /hello {
    content_by_lua "
      ngx.say('Hello, from inline lua')
    ";
  }

  location /hellofile {
    content_by_lua_file /etc/nginx/lua/hello.lua;
  }
}

$ sudo ln -s /etc/nginx/sites-available/dl.sample.com /etc/nginx/sites-enable/

luaファイル作成(location /hellofileで呼び出されるもの)

$ sudo mkdir /etc/nginx/lua
$ sudo vim /etc/nginx/lua/hello.lua
ngx.say("hello by file")

動作確認

$ sudo service nginx restart
$ curl https://dl.sample.com/hello
Hello, from inline lua
$ curl https://dl.sample.com/hellofile
hello by file

Range Requestsの実装

nginxのsite設定

$ sudo vim /etc/nginx/sites-available/dl.sample.com

server {
  listen  443 ssl;
  server_name dl.sample.com;
  location / {
    root  /var/www/html;
  }

  location ~ /v0/(.*\.mp4) {
    set $video_path $1;
    content_by_lua_file /etc/nginx/lua/v0/anymp4.lua;
  }

}

任意のファイル名でアクセスできるように(.*.mp4)設定。

luaファイル作成(location /v0/(.*.mp4) で呼び出されるもの)

$ sudo mkdir /etc/nginx/lua/v0
$ sudo vim /etc/nginx/lua/v0/anymp4.lua
function io.file_size(filename)
  local fh = assert(io.open(filename, "rb"))
  local len = assert(fh:seek("end"))
  fh.close()
  return len
end

function table.in_key(tbl, key)
  for k, v in pairs(tbl) do
    if k==key then return true end
  end
end

local video_path = ngx.unescape_uri(ngx.var.video_path)
local video_dir = "/mnt/mp4/"
local filename = video_dir..video_path

local h = ngx.req.get_headers()

local instance_length = io.file_size(filename)
if table.in_key(h, "range") then
  -- Range requests
  local reqRange = h["range"]
  local first_byte_pos = 0
  local last_byte_pos = instance_length - 1

  local reqFirst, reqLast = string.match(reqRange, "(%d*)-(%d*)")
  first_byte_pos = reqFirst

  if reqLast == "" then
    -- nothing to do
  else
    last_byte_pos = tonumber(reqLast)
  end

  -- Status code
  ngx.status = ngx.HTTP_PARTIAL_CONTENT

  -- Response headers
  contentLength = last_byte_pos - first_byte_pos + 1
  ngx.header["Content-Length"] = contentLength
  ngx.header["Content-Range"] = "bytes "..first_byte_pos.."-"..last_byte_pos.."/"..instance_length

  -- output stream
  local file = io.open(filename)
  file:seek("set", tonumber(reqFirst))
  local f = file:read(contentLength)
  ngx.print(f)
else
  -- Normal requests
  ngx.header["Content-Length"] = instance_length

  -- Status code
  ngx.status = ngx.HTTP_OK

  -- output stream
  local file = io.open(filename)
  local f = file:read("*all")
  ngx.print(f)
  ngx.flush(true)
end

RFC7233に従い、リクエスト時にHTTPヘッダ内にrangeがあれば、
206(HTTP_PARTIAL_CONTENT)と指定された範囲のデータを送信する。

動作確認

$ sudo service nginx restart
$ ls /mnt/mp4/
1.mp4

任意のmp4ファイル(この例では1.mp4)をanymp4.luaで指定したフォルダ(この例では/mnt/mp4/)に格納しておく。

chromeで下記のようなアドレスへアクセスすると、mp4閲覧時にシーク可能となっていることが確認できる。
https://dl.sample.com/v0/1.mp4

参考

http://techhey.hatenablog.com/entry/2014/04/17/200831
https://triple-underscore.github.io/RFC7233-ja.html

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?