Skip to content

Commit 1062805

Browse files
committed
Fix. read callback hangup if it returns wrong value
1 parent 05272ea commit 1062805

3 files changed

Lines changed: 256 additions & 10 deletions

File tree

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ before_install:
1717
- bash .travis/setup_lua.sh
1818
- sudo luarocks install lunitx
1919
- sudo pip install cpp-coveralls
20+
- sudo luarocks install dkjson
2021

2122
install:
2223
- sudo luarocks make rockspecs/lcurl-scm-0.rockspec CFLAGS="-O2 -fPIC -ftest-coverage -fprofile-arcs" LIBFLAG="-shared --coverage"

src/lceasy.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -696,15 +696,38 @@ static size_t lcurl_read_callback(lua_State *L,
696696

697697
n = lcurl_util_push_cb(L, rd);
698698
lua_pushinteger(L, ret);
699-
if(lua_pcall(L, n, LUA_MULTRET, 0)) return CURL_READFUNC_ABORT;
699+
if(lua_pcall(L, n, LUA_MULTRET, 0)){
700+
assert(lua_gettop(L) >= top);
701+
lua_pushlightuserdata(L, (void*)LCURL_ERROR_TAG);
702+
lua_insert(L, top+1);
703+
return CURL_READFUNC_ABORT;
704+
}
700705

701-
if(lua_isnoneornil(L, top + 1)){
702-
if(lua_gettop(L) <= (top + 1))return 0;
706+
if(lua_gettop(L) == top){
707+
return CURL_READFUNC_ABORT;
708+
}
709+
710+
assert(lua_gettop(L) >= top);
711+
712+
if(lua_type(L, top + 1) != LUA_TSTRING){
713+
if(lua_isnil(L, top + 1)){
714+
if(lua_gettop(L) == (top+1)) lua_settop(L, top);
715+
}
716+
else{
717+
if(lua_type(L, top + 1) == LUA_TNUMBER){
718+
size_t ret = lua_tonumber(L, top + 1);
719+
if(ret == (size_t)CURL_READFUNC_PAUSE){
720+
lua_settop(L, top);
721+
return CURL_READFUNC_PAUSE;
722+
}
723+
}
724+
lua_settop(L, top);
725+
}
703726
return CURL_READFUNC_ABORT;
704727
}
705-
data = lua_tolstring(L, -1, &data_size);
706-
if(!data) return CURL_READFUNC_ABORT;
707728

729+
data = lua_tolstring(L, top + 1, &data_size);
730+
assert(data);
708731
if(data_size > ret){
709732
data_size = ret;
710733
rbuffer->ref = luaL_ref(L, LCURL_LUA_REGISTRY);

test/test_easy.lua

Lines changed: 227 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ local skip = lunit.skip or function() end
55

66
local curl = require "lcurl"
77
local scurl = require "lcurl.safe"
8+
local json = require "dkjson"
89
local url = "http://example.com"
910
local fname = "./test.download"
1011

@@ -17,7 +18,9 @@ local function gc_collect()
1718
collectgarbage("collect")
1819
end
1920

20-
local _ENV = TEST_CASE'write_callback' do
21+
local ENABLE = true
22+
23+
local _ENV = TEST_CASE'write_callback' if ENABLE then
2124

2225
local c, f
2326

@@ -84,6 +87,9 @@ function test_reset_write_callback()
8487
assert_equal(c, c:setopt_writefunction(f))
8588
assert_equal(c, c:setopt_writefunction(f.write, f))
8689
assert_equal(c, c:setopt_writefunction(print))
90+
assert_error(function()c:setopt_writefunction()end)
91+
assert_error(function()c:setopt_writefunction(nil)end)
92+
assert_error(function()c:setopt_writefunction(nil, f)end)
8793
end
8894

8995
function test_write_pass_01()
@@ -113,10 +119,9 @@ function test_write_pass_03()
113119
assert_equal(c, c:perform())
114120
end
115121

116-
117122
end
118123

119-
local _ENV = TEST_CASE'progress_callback' do
124+
local _ENV = TEST_CASE'progress_callback' if ENABLE then
120125

121126
local c
122127

@@ -225,7 +230,224 @@ end
225230

226231
end
227232

228-
local _ENV = TEST_CASE'escape' do
233+
local _ENV = TEST_CASE'header_callback' if ENABLE then
234+
235+
local c, f
236+
local function dummy() end
237+
238+
function teardown()
239+
if c then c:close() end
240+
f, c = nil
241+
end
242+
243+
function test_header_abort_01()
244+
c = assert(scurl.easy{
245+
url = url;
246+
writefunction = dummy,
247+
headerfunction = function(str) return #str - 1 end;
248+
})
249+
250+
local _, e = assert_nil(c:perform())
251+
assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e)
252+
end
253+
254+
function test_header_abort_02()
255+
c = assert(scurl.easy{
256+
url = url;
257+
writefunction = dummy,
258+
headerfunction = function(str) return false end;
259+
})
260+
261+
local _, e = assert_nil(c:perform())
262+
assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e)
263+
end
264+
265+
function test_header_abort_03()
266+
c = assert(scurl.easy{
267+
url = url;
268+
writefunction = dummy,
269+
headerfunction = function(str) return nil, "WRITEERROR" end;
270+
})
271+
272+
local _, e = assert_nil(c:perform())
273+
assert_equal("WRITEERROR", e)
274+
end
275+
276+
function test_header_abort_04()
277+
c = assert(scurl.easy{
278+
url = url;
279+
writefunction = dummy,
280+
headerfunction = function(str) return nil end;
281+
})
282+
283+
local _, e = assert_nil(c:perform())
284+
assert_equal(curl.error(curl.ERROR_EASY, curl.E_WRITE_ERROR), e)
285+
end
286+
287+
function test_reset_header_callback()
288+
f = {header = function() end}
289+
c = assert(curl.easy{url = url})
290+
assert_equal(c, c:setopt_headerfunction(f))
291+
assert_equal(c, c:setopt_headerfunction(f.header, f))
292+
assert_equal(c, c:setopt_headerfunction(print))
293+
assert_error(function()c:setopt_headerfunction()end)
294+
assert_error(function()c:setopt_headerfunction(nil)end)
295+
assert_error(function()c:setopt_headerfunction(nil, f)end)
296+
end
297+
298+
function test_header_pass_01()
299+
c = assert(curl.easy{
300+
url = url;
301+
writefunction = dummy,
302+
headerfunction = function(s) return #s end
303+
})
304+
305+
assert_equal(c, c:perform())
306+
end
307+
308+
function test_header_pass_02()
309+
c = assert(curl.easy{
310+
url = url;
311+
writefunction = dummy,
312+
headerfunction = function() return end
313+
})
314+
315+
assert_equal(c, c:perform())
316+
end
317+
318+
function test_header_pass_03()
319+
c = assert(curl.easy{
320+
url = url;
321+
writefunction = dummy,
322+
headerfunction = function() return true end
323+
})
324+
325+
assert_equal(c, c:perform())
326+
end
327+
328+
329+
end
330+
331+
local _ENV = TEST_CASE'reader_callback' if ENABLE then
332+
333+
local url = "http://httpbin.org/post"
334+
335+
local c, f, t
336+
337+
local function get_bin_by(str,n)
338+
local pos = 1 - n
339+
return function()
340+
pos = pos + n
341+
return (str:sub(pos,pos+n-1))
342+
end
343+
end
344+
345+
local function strem(ch, n, m)
346+
return n, get_bin_by( (ch):rep(n), m)
347+
end
348+
349+
local function json_data()
350+
return json.decode(table.concat(t))
351+
end
352+
353+
function setup()
354+
t = {}
355+
f = assert(scurl.form())
356+
c = assert(scurl.easy{
357+
url = url,
358+
})
359+
assert_equal(c, c:setopt_writefunction(table.insert, t))
360+
end
361+
362+
function teardown()
363+
if f then f:free() end
364+
if c then c:close() end
365+
t, f, c = nil
366+
end
367+
368+
function test()
369+
assert_equal(f, f:add_stream('SSSSS', strem('X', 128, 13)))
370+
assert_equal(c, c:setopt_httppost(f))
371+
assert_equal(c, c:perform())
372+
assert_equal(200, c:getinfo_response_code())
373+
local data = assert_table(json_data())
374+
assert_table(data.form)
375+
assert_equal(('X'):rep(128), data.form.SSSSS)
376+
end
377+
378+
function test_abort_01()
379+
assert_equal(f, f:add_stream('SSSSS', 128, function() end))
380+
assert_equal(c, c:setopt_httppost(f))
381+
382+
local _, e = assert_nil(c:perform())
383+
assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e)
384+
end
385+
386+
function test_abort_02()
387+
assert_equal(f, f:add_stream('SSSSS', 128, function() return nil, "READERROR" end))
388+
assert_equal(c, c:setopt_httppost(f))
389+
390+
local _, e = assert_nil(c:perform())
391+
assert_equal("READERROR", e)
392+
end
393+
394+
function test_abort_03()
395+
assert_equal(f, f:add_stream('SSSSS', 128, function() return 1 end))
396+
assert_equal(c, c:setopt_httppost(f))
397+
398+
local _, e = assert_nil(c:perform())
399+
assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e)
400+
end
401+
402+
function test_abort_04()
403+
assert_equal(f, f:add_stream('SSSSS', 128, function() return true end))
404+
assert_equal(c, c:setopt_httppost(f))
405+
406+
local _, e = assert_nil(c:perform())
407+
assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), e)
408+
end
409+
410+
function test_abort_04()
411+
assert_equal(f, f:add_stream('SSSSS', 128, function() error("READERROR") end))
412+
assert_equal(c, c:setopt_httppost(f))
413+
414+
assert_error_match("READERROR", function() c:perform() end)
415+
end
416+
417+
function test_pause()
418+
local counter = 0
419+
assert_equal(f, f:add_stream('SSSSS', 128, function()
420+
if counter == 0 then
421+
counter = counter + 1
422+
return curl.READFUNC_PAUSE
423+
end
424+
if counter == 1 then
425+
counter = counter + 1
426+
return ('X'):rep(128)
427+
end
428+
return ''
429+
end))
430+
431+
assert_equal(c, c:setopt_progressfunction(function()
432+
if counter == 1 then
433+
c:pause(curl.PAUSE_CONT)
434+
end
435+
end))
436+
437+
assert_equal(c, c:setopt_noprogress(false))
438+
439+
assert_equal(c, c:setopt_httppost(f))
440+
441+
assert_equal(c, c:perform())
442+
assert_equal(200, c:getinfo_response_code())
443+
local data = assert_table(json_data())
444+
assert_table(data.form)
445+
assert_equal(('X'):rep(128), data.form.SSSSS)
446+
end
447+
448+
end
449+
450+
local _ENV = TEST_CASE'escape' if ENABLE then
229451

230452
local c
231453

@@ -244,7 +466,7 @@ end
244466

245467
end
246468

247-
local _ENV = TEST_CASE'setopt_form' do
469+
local _ENV = TEST_CASE'setopt_form' if ENABLE then
248470

249471
local c
250472

0 commit comments

Comments
 (0)