Fix. read callback hangup if it returns wrong value

master
Alexey Melnichuk 2014-09-07 13:54:54 +04:00
parent 05272ea096
commit 1062805482
3 changed files with 257 additions and 11 deletions

View File

@ -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"

View File

@ -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);

View File

@ -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