diff --git a/.travis.yml b/.travis.yml index d15e941..a2f8b17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ before_install: - bash .travis/setup_lua.sh - sudo luarocks install lunitx - sudo pip install cpp-coveralls + - sudo luarocks install dkjson install: - sudo luarocks make rockspecs/lcurl-scm-0.rockspec CFLAGS="-O2 -fPIC -ftest-coverage -fprofile-arcs" LIBFLAG="-shared --coverage" diff --git a/src/lceasy.c b/src/lceasy.c index d47552c..af6bcfe 100644 --- a/src/lceasy.c +++ b/src/lceasy.c @@ -696,15 +696,38 @@ static size_t lcurl_read_callback(lua_State *L, n = lcurl_util_push_cb(L, rd); lua_pushinteger(L, ret); - if(lua_pcall(L, n, LUA_MULTRET, 0)) return CURL_READFUNC_ABORT; - - if(lua_isnoneornil(L, top + 1)){ - if(lua_gettop(L) <= (top + 1))return 0; + if(lua_pcall(L, n, LUA_MULTRET, 0)){ + assert(lua_gettop(L) >= top); + lua_pushlightuserdata(L, (void*)LCURL_ERROR_TAG); + lua_insert(L, top+1); return CURL_READFUNC_ABORT; } - data = lua_tolstring(L, -1, &data_size); - if(!data) return CURL_READFUNC_ABORT; + if(lua_gettop(L) == top){ + return CURL_READFUNC_ABORT; + } + + assert(lua_gettop(L) >= top); + + if(lua_type(L, top + 1) != LUA_TSTRING){ + if(lua_isnil(L, top + 1)){ + if(lua_gettop(L) == (top+1)) lua_settop(L, top); + } + else{ + if(lua_type(L, top + 1) == LUA_TNUMBER){ + size_t ret = lua_tonumber(L, top + 1); + if(ret == (size_t)CURL_READFUNC_PAUSE){ + lua_settop(L, top); + return CURL_READFUNC_PAUSE; + } + } + lua_settop(L, top); + } + return CURL_READFUNC_ABORT; + } + + data = lua_tolstring(L, top + 1, &data_size); + assert(data); if(data_size > ret){ data_size = ret; rbuffer->ref = luaL_ref(L, LCURL_LUA_REGISTRY); diff --git a/test/test_easy.lua b/test/test_easy.lua index bc48889..773e297 100644 --- a/test/test_easy.lua +++ b/test/test_easy.lua @@ -5,6 +5,7 @@ local skip = lunit.skip or function() end local curl = require "lcurl" local scurl = require "lcurl.safe" +local json = require "dkjson" local url = "http://example.com" local fname = "./test.download" @@ -17,7 +18,9 @@ local function gc_collect() collectgarbage("collect") end -local _ENV = TEST_CASE'write_callback' do +local ENABLE = true + +local _ENV = TEST_CASE'write_callback' if ENABLE then local c, f @@ -84,6 +87,9 @@ function test_reset_write_callback() assert_equal(c, c:setopt_writefunction(f)) assert_equal(c, c:setopt_writefunction(f.write, f)) assert_equal(c, c:setopt_writefunction(print)) + assert_error(function()c:setopt_writefunction()end) + assert_error(function()c:setopt_writefunction(nil)end) + assert_error(function()c:setopt_writefunction(nil, f)end) end function test_write_pass_01() @@ -113,10 +119,9 @@ function test_write_pass_03() assert_equal(c, c:perform()) end - end -local _ENV = TEST_CASE'progress_callback' do +local _ENV = TEST_CASE'progress_callback' if ENABLE then local c @@ -225,7 +230,224 @@ end end -local _ENV = TEST_CASE'escape' do +local _ENV = TEST_CASE'header_callback' if ENABLE then + +local c, f +local function dummy() end + +function teardown() + if c then c:close() end + f, c = nil +end + +function test_header_abort_01() + c = assert(scurl.easy{ + url = url; + writefunction = dummy, + headerfunction = function(str) return #str - 1 end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) +end + +function test_header_abort_02() + c = assert(scurl.easy{ + url = url; + writefunction = dummy, + headerfunction = function(str) return false end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) +end + +function test_header_abort_03() + c = assert(scurl.easy{ + url = url; + writefunction = dummy, + headerfunction = function(str) return nil, "WRITEERROR" end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal("WRITEERROR", e) +end + +function test_header_abort_04() + c = assert(scurl.easy{ + url = url; + writefunction = dummy, + headerfunction = function(str) return nil end; + }) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e) +end + +function test_reset_header_callback() + f = {header = function() end} + c = assert(curl.easy{url = url}) + assert_equal(c, c:setopt_headerfunction(f)) + assert_equal(c, c:setopt_headerfunction(f.header, f)) + assert_equal(c, c:setopt_headerfunction(print)) + assert_error(function()c:setopt_headerfunction()end) + assert_error(function()c:setopt_headerfunction(nil)end) + assert_error(function()c:setopt_headerfunction(nil, f)end) +end + +function test_header_pass_01() + c = assert(curl.easy{ + url = url; + writefunction = dummy, + headerfunction = function(s) return #s end + }) + + assert_equal(c, c:perform()) +end + +function test_header_pass_02() + c = assert(curl.easy{ + url = url; + writefunction = dummy, + headerfunction = function() return end + }) + + assert_equal(c, c:perform()) +end + +function test_header_pass_03() + c = assert(curl.easy{ + url = url; + writefunction = dummy, + headerfunction = function() return true end + }) + + assert_equal(c, c:perform()) +end + + +end + +local _ENV = TEST_CASE'reader_callback' if ENABLE then + +local url = "http://httpbin.org/post" + +local c, f, t + +local function get_bin_by(str,n) + local pos = 1 - n + return function() + pos = pos + n + return (str:sub(pos,pos+n-1)) + end +end + +local function strem(ch, n, m) + return n, get_bin_by( (ch):rep(n), m) +end + +local function json_data() + return json.decode(table.concat(t)) +end + +function setup() + t = {} + f = assert(scurl.form()) + c = assert(scurl.easy{ + url = url, + }) + assert_equal(c, c:setopt_writefunction(table.insert, t)) +end + +function teardown() + if f then f:free() end + if c then c:close() end + t, f, c = nil +end + +function test() + assert_equal(f, f:add_stream('SSSSS', strem('X', 128, 13))) + assert_equal(c, c:setopt_httppost(f)) + assert_equal(c, c:perform()) + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + assert_table(data.form) + assert_equal(('X'):rep(128), data.form.SSSSS) +end + +function test_abort_01() + assert_equal(f, f:add_stream('SSSSS', 128, function() end)) + assert_equal(c, c:setopt_httppost(f)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_02() + assert_equal(f, f:add_stream('SSSSS', 128, function() return nil, "READERROR" end)) + assert_equal(c, c:setopt_httppost(f)) + + local _, e = assert_nil(c:perform()) + assert_equal("READERROR", e) +end + +function test_abort_03() + assert_equal(f, f:add_stream('SSSSS', 128, function() return 1 end)) + assert_equal(c, c:setopt_httppost(f)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_04() + assert_equal(f, f:add_stream('SSSSS', 128, function() return true end)) + assert_equal(c, c:setopt_httppost(f)) + + local _, e = assert_nil(c:perform()) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e) +end + +function test_abort_04() + assert_equal(f, f:add_stream('SSSSS', 128, function() error("READERROR") end)) + assert_equal(c, c:setopt_httppost(f)) + + assert_error_match("READERROR", function() c:perform() end) +end + +function test_pause() + local counter = 0 + assert_equal(f, f:add_stream('SSSSS', 128, function() + if counter == 0 then + counter = counter + 1 + return curl.READFUNC_PAUSE + end + if counter == 1 then + counter = counter + 1 + return ('X'):rep(128) + end + return '' + end)) + + assert_equal(c, c:setopt_progressfunction(function() + if counter == 1 then + c:pause(curl.PAUSE_CONT) + end + end)) + + assert_equal(c, c:setopt_noprogress(false)) + + assert_equal(c, c:setopt_httppost(f)) + + assert_equal(c, c:perform()) + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + assert_table(data.form) + assert_equal(('X'):rep(128), data.form.SSSSS) +end + +end + +local _ENV = TEST_CASE'escape' if ENABLE then local c @@ -244,7 +466,7 @@ end end -local _ENV = TEST_CASE'setopt_form' do +local _ENV = TEST_CASE'setopt_form' if ENABLE then local c