openresty / lua-resty-upload

Streaming reader and parser for http file uploading based on ngx_lua cosocket
404 stars 113 forks source link

Attempt to index local 'form' (a nil value) #26

Open zayednetad opened 8 years ago

zayednetad commented 8 years ago

Hi, I am following below code on fedora Linux with nginx:

        local resty_sha256 = require "resty.sha256"
        local upload = require "resty.upload"

        local chunk_size = 4096
        local form = upload:new(chunk_size)
        local sha256 = resty_sha256:new()
        local file

        local upload_path = '/tmp/uploads/'

        while true do
           local typ, res, err = form:read()

            if not typ then
                ngx.say("failed to read: ", err)
                return
            end

            if typ == "header" then
                local file_name = upload_path .. ngx.time()
                if file_name then
                    file = io.open(file_name, 'w+')
                    if not file then
                        ngx.say("failed to open file ", file_name)
                        return
                    end
                end
            elseif typ == "body" then
                if file then
                    file:write(res)
                    sha256:update(res)
                end
            elseif typ == "part_end" then
                file:close()
                file = nil
            elseif typ == "eof" then
                break
            else
                -- nothing
            end
        end

        local digest = sha256:final()
        sha256:reset()

        local str = require "resty.string"
        ngx.say("sha256: ", str.to_hex(digest))```

When I run this as

curl -F "filename=@shatest.lua" http://127.0.0.1:8089/uploadtest

It gives me below errors:

$ tail -f /usr/local/openresty/nginx/logs/error.log 2016/06/29 15:26:23 [error] 31449#0: *12 lua entry thread aborted: runtime error: /usr/local/openresty/nginx/uploadtest.lua:13: attempt to index local 'form' (a nil value) stack traceback: coroutine 0: /usr/local/openresty/nginx/uploadtest.lua: in function </usr/local/openresty/nginx/uploadtest.lua:1>, client: 127.0.0.1, server: localhost, request: "POST /uploadtest HTTP/1.1", host: "127.0.0.1:8089"

Can you please help me what is wrong here?

agentzh commented 8 years ago

@zayednetad The new method may fail. You should handle any error returned from it. As in the document example:

                local form, err = upload:new(chunk_size)
                if not form then
                    ngx.log(ngx.ERR, "failed to new upload: ", err)
                    ngx.exit(500)
                end
zayednetad commented 8 years ago

Now it says below:

2016/07/01 00:14:36 [error] 19582#0: *3 [lua] uploadtest.lua:7: failed to new upload: request body already exists, client: 127.0.0.1, server: localhost, request: "POST /uploadtest HTTP/1.1", host: "127.0.0.1:8089"

agentzh commented 8 years ago

The error message clearly indicates that the request body has already been read by something else.

Ensue you do not turn on the lua_need_request_body directive in your nginx.conf and do not call ngx.req.read_body() nor ngx.req.discard_body(), for example. All these would consume the request body before this library can get its hands on it.

whoszus commented 6 years ago

With the same issues , but i got nothing like ngx.req.read_body() nor ngx.req.discard_body() in nginx.conf ;what's the next step should i take to resolve it ? Here 's the code

local upload = require "resty.upload"
local cjson = require "cjson"

local chunk_size = 4096
local form ,err = upload:new(chunk_size)
if not form then
    ngx.log(ngx.ERR, "failed to new upload: ", err)
    -- ngx.say(cjson.encode({code=501, msg='ext err', data=res}))
    ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end
form:set_timeout(500)
local conf = {max_size=1000000, allow_exts={'jpg', 'png', 'gif'}}
local file
local file_name

function get_ext(res)
    local ext = 'jpg'
    if res == 'image/png' then
        ext = 'png'
    elseif res == 'image/jpg' or res == 'image/jpeg' then
        ext = 'jpg'
    elseif res == 'image/gif' then
        ext = 'gif'
    end
    return ext
end

function getLocalIP()
    os.execute("/sbin/ifconfig|sed -n '/inet addr/s/^[^:]*:\\([0-9.]\\{7,15\\}\\) .*/\\1/p' > ip.info");
    local_ip_list = {}
    local_ip_file = assert(io.open("ip.info", "r"))

    for line in local_ip_file:lines() do
      local_ip_list[#local_ip_list + 1] = line
    end

    local_ip_file:close();
    print(table.concat(local_ip_list,';'));
    ngx.log(ngx.INFO,"ip addr:"..local_ip_list)
    return local_ip_list;
end

local random = math.random
local function uuid()
    local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
    return string.gsub(template, '[xy]', function (c)
        local v = (c == 'x') and random(0, 0xf) or random(8, 0xb)
        return string.format('%x', v)
    end)
end

local function uuid2()
     local template ="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
     d = io.open("/dev/urandom", "r"):read(4)
     math.randomseed(os.time() + d:byte(1) + (d:byte(2) * 256) + (d:byte(3) * 65536) + (d:byte(4) * 4294967296))
     return string.gsub(template, "x", function (c)
      local v = (c == "x") and math.random(0, 0xf) or math.random(8, 0xb)
      return string.format("%x", v)
      end)
end

function in_array(v, tab)
    local i = false
    for _, val in ipairs(tab) do
        if val == v then
            i = true
            break
        end
    end
    return i
end

function get_filename(res)  
    local filename = ngx.re.match(res,'(.+)filename="(.+)"(.*)')
    if filename then   
        return filename[2]  
    end  
end  

while true do
    local typ, res, err = form:read() 
    if not typ then
        ngx.say(cjson.encode({code=502, msg='failed to read:', data=err}))
        return
    end
    if typ == "header" then
        if res[1] == "Content-Disposition" then
            math.randomseed(tostring(os.time()):reverse():sub(1, 6))
            local file_id = uuid2()
            local extension = get_ext(res[2])
            local fileName = get_filename(res[2])
            ngx.log(ngx.INFO,extension);
            ngx.log(ngx.ERR,filename)
            -- getLocalIP();
            if not extension then
                 ngx.say(cjson.encode({code=501, msg='ext not found', data=res}))
                 return 
            end

            if not in_array(extension, conf.allow_exts) then
                ngx.say(cjson.encode({code=501, msg='deny', data=res}))
                return 
            end

            local dir = '/home/tinker/temp/upload/'..os.date('%Y')..os.date('%m')..os.date('%d')..'/'   
            local status = os.execute('mkdir -p '..dir)
            if status ~= 0 then
                ngx.say(cjson.encode({code=501, msg='mkdir exp'}))
                return
            end  
            file_name = dir..file_id.."."..extension          
            if file_name then
                file = io.open(file_name, "w+")
                if not file then
                    ngx.say(cjson.encode({code=500, msg='failed to open file',imgurl=''}))
                    return
                end
            end
        end
     elseif typ == "body" then
        if type(tonumber(res)) == 'number' and tonumber(res) > conf.max_size then
            ngx.say(cjson.encode({code=501, msg='oversize', data=res}))
            return
        end
        if file then
            file:write(res)            
        end
    elseif typ == "part_end" then
        if file then
            file:close()
            file = nil
        end
    elseif typ == "eof" then
        file_name = string.gsub(file_name, '/home/tinker/temp/upload/', '')

        ngx.say(cjson.encode({code=200, msg='great',imgurl= file_name}))
        break
    else

    end
end

this line "ngx.log(ngx.ERR,filename) " logs a nil ;