diff --git a/backend_file_storage_handler.lua b/backend_file_storage_handler.lua index 4faefda..d838510 100644 --- a/backend_file_storage_handler.lua +++ b/backend_file_storage_handler.lua @@ -10,31 +10,60 @@ local ngx = ngx local string = string local concat = table.concat local error = error - +local os = os module(...) local function end_backend(self, ctx) -- last chunk commited? if ctx.range_to + 1 == ctx.range_total then + + -- seed body arguments into table.. + local body_args = { + size = ctx.range_total, + id = ctx.id, + path = ctx.file_path, + name = ctx.get_name(), + file_name = ctx.file_name, + checksum = ctx.checksum, + sha1 = ctx.sha1 + } + + -- parameterize misc value if populated.. + -- note: misc must be a string of uri-style parameters. i.e. a=1&b=2 + -- fucking nginx strips inbound complex key->value tables into simple string arrays + if ctx.misc ~= nil then + for kv in string.gmatch(ctx.misc, "[^&]+") do + for k, v in string.gmatch(kv, "(%w.+)=(%w.+)") do + body_args[k] = v + end + end + end + ngx.req.set_header('Content-Type', 'application/x-www-form-urlencoded') return ngx.location.capture(self.backend, { method = ngx.HTTP_POST, - body = ngx.encode_args({ - size = ctx.range_total, - id = ctx.id, - path = ctx.file_path, - name = ctx.get_name(), - checksum = ctx.checksum, - sha1 = ctx.sha1 - }) + body = ngx.encode_args(body_args) }) end end +local function move_file(self, ctx) + if ctx.file_path and ctx.success_destination_dir then + local ret, err = os.rename(ctx.file_path, concat({ctx.success_destination_dir, ctx.file_name}, "/")) + if ret == nil or err ~= nil then + return string.format("Failed to move completed file: %s to: %s. Error: %s", ctx.file_path, ctx.success_destination_dir, err) + end + end +end + -- override local function on_body_start(self, ctx) local file_path = concat({self.dir, ctx.id}, "/") + if ctx.file_name ~= nil then + -- use explicitly specified filename.. + file_path = concat({self.dir, ctx.file_name}, "/") + end ctx.file_path = file_path return self:init_file(ctx) end @@ -42,7 +71,14 @@ end -- override local function on_body_end(self, ctx) self:close_file() - -- call backend if finished + if ctx.range_to + 1 == ctx.range_total then + local ret = move_file(self, ctx) + if ret then + ngx.log(ngx.ERR, ret) + return ngx.ERROR + end + end + -- call backend if finished & move successful local res = end_backend(self, ctx) return {201, string.format("0-%d/%d", ctx.range_to, ctx.range_total), response = res } end diff --git a/big-upload.lua b/big-upload.lua index 38afb9f..6f9f8d7 100644 --- a/big-upload.lua +++ b/big-upload.lua @@ -4,7 +4,8 @@ local config = { package_path = ngx.var.package_path, bu_checksum = ('on' == ngx.var.bu_checksum), - bu_sha1 = ('on' == ngx.var.bu_sha1) + bu_sha1 = ('on' == ngx.var.bu_sha1), + bu_mime = ('on' == ngx.var.bu_mime) } if config.package_path then @@ -15,6 +16,7 @@ local file_storage_handler = require "file_storage_handler" local backend_file_storage_handler = require "backend_file_storage_handler" local crc32 = require('crc32') local sha1= require('sha1_handler') +local mime = require('mime') local function report_result(info) if type(info) == "table" then @@ -62,7 +64,10 @@ if config.bu_checksum then table.insert(handlers, crc32.handler()) end if config.bu_sha1 then - table.insert(handlers, sha1.handler(ngx.var.file_storage_path)) + table.insert(handlers, sha1.handler(ngx.var.file_storage_path)) +end +if config.bu_mime then + table.insert(handlers, mime.handler()) end table.insert(handlers, storage_handler) diff --git a/crc32.lua b/crc32.lua index c6aa077..985013e 100644 --- a/crc32.lua +++ b/crc32.lua @@ -2,21 +2,20 @@ -- CRC32 checksum -local ffi = require('ffi') local tonumber = tonumber local string = string local ngx = ngx local table = table + +local zlib = require ('zlib') + module(...) -local zlib = ffi.load('z') -ffi.cdef[[ - unsigned long crc32(unsigned long crc, const char *buf, unsigned len ); -]] function crc32(data, lastnum) - return tonumber(zlib.crc32(lastnum, data, #data)) + return zlib.crc32()(data, lastnum) + -- return zlib.crc32()(lastnum, data, #data) end function validhex(crchex) return #crchex <= 8 and string.match(crchex, "^%x+$") end @@ -32,6 +31,7 @@ function handler() return { on_body_start = function (self, ctx) ctx.current_checksum = ctx.last_checksum and tonumber(ctx.last_checksum, 16) or ( ctx.first_chunk and 0 ) + -- stop checksum processing if X-Last-Checksum is not present for non first chunk if not ctx.current_checksum then self.on_body = nil @@ -40,12 +40,13 @@ function handler() end, on_body = function (self, ctx, body) - ctx.current_checksum = crc32(body, ctx.current_checksum) + ctx.current_checksum = crc32(body, ctx.current_checksum) end, on_body_end = function (self, ctx) if ctx.checksum then if tonumber(ctx.checksum,16) ~= ctx.current_checksum then + ngx.log(ngx.ERR, string.format("Chunk checksum mismatch client=[%s] server=[%s]", ctx.checksum, tohex(ctx.current_checksum))) return {400, string.format("Chunk checksum mismatch client=[%s] server=[%s]", ctx.checksum, tohex(ctx.current_checksum))} end else diff --git a/example/html/index.html b/example/html/index.html index d58070a..ede00a2 100644 --- a/example/html/index.html +++ b/example/html/index.html @@ -22,14 +22,17 @@

Example Chunked Uploader