diff --git a/.travis.yml b/.travis.yml index 856b696..d15e941 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,7 @@ script: - lunit.sh test_easy.lua - lunit.sh test_safe.lua - lunit.sh test_form.lua + - lunit.sh test_pause02.c.lua after_success: - coveralls -b .. -r .. diff --git a/doc/lcurl.ldoc b/doc/lcurl.ldoc index 86d6841..3b6fef3 100644 --- a/doc/lcurl.ldoc +++ b/doc/lcurl.ldoc @@ -205,6 +205,12 @@ function unescape() end -- @treturn easy self function reset() end +--- Pause and unpause a connection. +-- +-- @tparam number mask set of bits that sets the new state of the connection (one of PAUSE_XXX constant) +-- @treturn easy self +function pause() end + --- End easy session -- function close() end diff --git a/lakefile b/lakefile index 1ba4e5d..d878bea 100644 --- a/lakefile +++ b/lakefile @@ -28,6 +28,7 @@ target('test', install, function() run_test('test_easy.lua') run_test('test_safe.lua') run_test('test_form.lua') + run_test('test_pause02.c.lua') if not test_summary() then quit("test fail") diff --git a/src/lceasy.c b/src/lceasy.c index bb4b458..f8da101 100644 --- a/src/lceasy.c +++ b/src/lceasy.c @@ -877,7 +877,7 @@ static int lcurl_easy_unsetopt(lua_State *L){ static int lcurl_easy_getinfo(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); - int opt = luaL_checklong(L, 2); + long opt = luaL_checklong(L, 2); lua_remove(L, 2); #define OPT_ENTRY(l, N, T, S) case CURLINFO_##N: return lcurl_easy_get_##N(L); @@ -889,6 +889,17 @@ static int lcurl_easy_getinfo(lua_State *L){ return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, LCURL_E_UNKNOWN_OPTION); } +static int lcurl_easy_pause(lua_State *L){ + lcurl_easy_t *p = lcurl_geteasy(L); + int mask = luaL_checkint(L, 2); + CURLcode code = curl_easy_pause(p->curl, mask); + if(code != CURLE_OK){ + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); + } + lua_settop(L, 1); + return 1; +} + //} static const struct luaL_Reg lcurl_easy_methods[] = { @@ -919,6 +930,7 @@ static const struct luaL_Reg lcurl_easy_methods[] = { #include "lcinfoeasy.h" #undef OPT_ENTRY + { "pause", lcurl_easy_pause }, { "reset", lcurl_easy_reset }, { "setopt", lcurl_easy_setopt }, { "getinfo", lcurl_easy_getinfo }, diff --git a/src/lcflags.h b/src/lcflags.h index b21daab..c1efbc8 100644 --- a/src/lcflags.h +++ b/src/lcflags.h @@ -146,3 +146,10 @@ FLG_ENTRY(PROXY_SOCKS4 ) /* added in 7.15.2 */ FLG_ENTRY(PROXY_SOCKS5 ) /* added in 7.10.0 */ FLG_ENTRY(PROXY_SOCKS4A ) /* added in 7.18.0 */ FLG_ENTRY(PROXY_SOCKS5_HOSTNAME ) /* added in 7.18.0 */ + +FLG_ENTRY(PAUSE_ALL ) /* added in 7.18.0 */ +FLG_ENTRY(PAUSE_CONT ) /* added in 7.18.0 */ +FLG_ENTRY(PAUSE_RECV ) /* added in 7.18.0 */ +FLG_ENTRY(PAUSE_RECV_CONT ) /* added in 7.18.0 */ +FLG_ENTRY(PAUSE_SEND ) /* added in 7.18.0 */ +FLG_ENTRY(PAUSE_SEND_CONT ) /* added in 7.18.0 */ diff --git a/src/lcopteasy.h b/src/lcopteasy.h index 7f8c17c..366da42 100644 --- a/src/lcopteasy.h +++ b/src/lcopteasy.h @@ -261,6 +261,9 @@ FLG_ENTRY( HTTP_VERSION_1_1 ) FLG_ENTRY( HTTP_VERSION_2_0 ) #endif +FLG_ENTRY( READFUNC_PAUSE ) /*7.18.0*/ +FLG_ENTRY( WRITEFUNC_PAUSE ) /*7.18.0*/ + #ifdef OPT_ENTRY_IS_NULL # undef OPT_ENTRY #endif diff --git a/test/test_pause02.c.lua b/test/test_pause02.c.lua new file mode 100644 index 0000000..a01628f --- /dev/null +++ b/test/test_pause02.c.lua @@ -0,0 +1,88 @@ +local curl = require "lcurl" + +-- How many times curl_multi_perform should be called before hitting of CURLPAUSE_CONT. +-- (including curl_multi_perform that causes WriteFunction to pause writes, +-- i.e. 1 means that CURLPAUSE_CONT will be performed immediately after pause.) +local WAIT_COUNT = 32 + +local RESOURCE_URL = "http://www.gutenberg.org/files/1257/old/1musk10.zip" + +local State = { + PAUSE = 0, -- write function should return CURL_WRITEFUNC_PAUSE + WAIT = 1, -- waiting for CURLPAUSE_CONT + WRITE = 2, -- write function should perform write + WRITTEN = 3, -- write function have performed write +} + +-- Current state +local state = State.PAUSE + +-- Countdown to continue writes +local waitCount = 0 + +-- Received data and data size +local data, datasize = {}, 0 + +local function WriteFunction(str) + if state == State.PAUSE then + state = State.WAIT + waitCount = WAIT_COUNT + return curl.WRITEFUNC_PAUSE + end + + if state == State.WAIT then + -- callback shouldn't be called in this state + print("WARNING: write-callback called in STATE_WAIT") + return curl.WRITEFUNC_PAUSE + end + + if state == State.WRITE then + state = State.WRITE + end + + datasize = datasize + #str + data[#data + 1] = str +end + +local function perform(multi, easy) + while true do + local handles = multi:perform() + + if state == State.WAIT then + waitCount = waitCount - 1 + if waitCount == 0 then + state = State.WRITE + easy:pause(curl.PAUSE_CONT) + end + end + + if state == State.WRITTEN then + state = State.PAUSE + break + end + + if 0 == handles then + local h, ok, err = multi:info_read() + return not not ok, err + end + + multi:wait() + end +end + +local easy = curl.easy{ + url = RESOURCE_URL, + accept_encoding = "gzip,deflate", + writefunction = WriteFunction, +} +local multi = curl.multi() +multi:add_handle(easy) + +local ok, err = perform(multi, easy) + +if ok then + print("OK: data retrieved successfully (" .. tostring(datasize) .. ")") +else + print("ERROR: data retrieve failed (" .. tostring(err) .. ")") + os.exit(1) +end