diff --git a/doc/lcurl.ldoc b/doc/lcurl.ldoc index e7016b9..14d6c7a 100644 --- a/doc/lcurl.ldoc +++ b/doc/lcurl.ldoc @@ -22,11 +22,13 @@ function easy() end --- Create Multi object -- +-- @tparam[opt] table options -- @treturn[1] multi new curl multi object function multi() end --- Create Share object -- +-- @tparam[opt] table options -- @treturn[1] share new curl share object function share() end @@ -379,12 +381,13 @@ function info_read() end --- Set options. -- --- @tparam number opt one of `curl.OPT_MULTI_XXX` constant +-- @tparam number|table opt one of `curl.OPT_MULTI_XXX` constant -- @param ... value -- @treturn multi self -- -- @usage -- c:setopt(curl.OPT_MULTI_MAXCONNECTS, 10) +-- c:setopt{maxconnects = 10} function setopt() end --- Set timer callback. @@ -430,12 +433,13 @@ do --- Set options. -- --- @tparam number opt one of `curl.OPT_SHARE_XXX` constant +-- @tparam number|table opt one of `curl.OPT_SHARE_XXX` constant -- @param ... value -- @treturn share self -- -- @usage -- c:setopt(curl.OPT_SHARE_SHARE, curl.LOCK_DATA_COOKIE) +-- c:setopt{share = curl.LOCK_DATA_COOKIE} function setopt() end --- End share session. diff --git a/src/lceasy.c b/src/lceasy.c index 88ef621..9c963d6 100644 --- a/src/lceasy.c +++ b/src/lceasy.c @@ -19,74 +19,6 @@ static const char *LCURL_EASY = LCURL_EASY_NAME; //{ -static void lcurl_easy_pcall_close(lua_State *L, int obj){ - int top = lua_gettop(L); - lua_pushvalue(L, obj); - lcurl_util_pcall_method(L, "close", 0, 0, 0); - lua_settop(L, top); -} - -static int lcurl_easy_apply_options(lua_State *L, lcurl_easy_t *p, int opt, int obj, int do_close){ - int top = lua_gettop(L); - opt = lua_absindex(L, opt); - obj = lua_absindex(L, obj); - - lua_pushnil(L); - while(lua_next(L, opt) != 0){ - int n; - assert(lua_gettop(L) == (top + 2)); - - if(lua_type(L, -2) == LUA_TNUMBER){ /* [curl.OPT_URL] = "http://localhost" */ - lua_pushvalue(L, -2); - lua_insert(L, -2); /*Stack : opt, obj, k, k, v */ - lua_pushliteral(L, "setopt"); /*Stack : opt, obj, k, k, v, "setopt" */ - n = 2; - } - else if(lua_type(L, -2) == LUA_TSTRING){ /* url = "http://localhost" */ - lua_pushliteral(L, "setopt_"); lua_pushvalue(L, -3); lua_concat(L, 2); - /*Stack : opt, obj, k, v, "setopt_XXX" */ - n = 1; - } - else{ - lua_pop(L, 1); - continue; - } - /*Stack : opt, obj, k,[ k,] v, `setoptXXX` */ - - lua_gettable(L, obj); /* get e["settop_XXX]*/ - - if(lua_isnil(L, -1)){ /* unknown option */ - if(do_close) lcurl_easy_pcall_close(L, obj); - lua_settop(L, top); - return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, LCURL_E_UNKNOWN_OPTION); - } - - lua_insert(L, -n-1); /*Stack : opt, obj, k, setoptXXX, [ k,] v */ - lua_pushvalue(L, obj); /*Stack : opt, obj, k, setoptXXX, [ k,] v, obj */ - lua_insert(L, -n-1); /*Stack : opt, obj, k, setoptXXX, obj, [ k,] v */ - - if(lua_pcall(L, n+1, 2, 0)){ - if(do_close) lcurl_easy_pcall_close(L, obj); - return lua_error(L); - } - - if(lua_isnil(L, -2)){ - if(do_close) lcurl_easy_pcall_close(L, obj); - lua_settop(L, top); - return 2; - } - - /*Stack : opt, obj, k, ok, nil*/ - lua_pop(L, 2); - assert(lua_gettop(L) == (top+1)); - } - assert(lua_gettop(L) == top); - return 0; -} - - - - int lcurl_easy_create(lua_State *L, int error_mode){ lcurl_easy_t *p; int i; @@ -111,7 +43,7 @@ int lcurl_easy_create(lua_State *L, int error_mode){ } if(lua_type(L, 1) == LUA_TTABLE){ - int ret = lcurl_easy_apply_options(L, p, 1, 2, 1); + int ret = lcurl_utils_apply_options(L, 1, 2, 1, p->err_mode, LCURL_ERROR_EASY, LCURL_E_UNKNOWN_OPTION); if(ret) return ret; assert(lua_gettop(L) == 2); } @@ -733,7 +665,7 @@ static int lcurl_easy_setopt(lua_State *L){ luaL_checkany(L, 2); if(lua_type(L, 2) == LUA_TTABLE){ - int ret = lcurl_easy_apply_options(L, p, 2, 1, 0); + int ret = lcurl_utils_apply_options(L, 2, 1, 0, p->err_mode, LCURL_ERROR_EASY, LCURL_E_UNKNOWN_OPTION); if(ret) return ret; lua_settop(L, 1); return 1; diff --git a/src/lcmulti.c b/src/lcmulti.c index 54d6f50..6171bc2 100644 --- a/src/lcmulti.c +++ b/src/lcmulti.c @@ -21,15 +21,27 @@ static const char *LCURL_ERROR_TAG = "LCURL_ERROR_TAG"; static const char *LCURL_MULTI = LCURL_MULTI_NAME; //{ + int lcurl_multi_create(lua_State *L, int error_mode){ - lcurl_multi_t *p = lutil_newudatap(L, lcurl_multi_t, LCURL_MULTI); + lcurl_multi_t *p; + + lua_settop(L, 1); + + p = lutil_newudatap(L, lcurl_multi_t, LCURL_MULTI); p->curl = curl_multi_init(); + p->err_mode = error_mode; if(!p->curl) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, CURLM_INTERNAL_ERROR); p->L = L; - p->err_mode = error_mode; lcurl_util_new_weak_table(L, "v"); p->h_ref = luaL_ref(L, LCURL_LUA_REGISTRY); p->tm.cb_ref = p->tm.ud_ref = LUA_NOREF; + + if(lua_type(L, 1) == LUA_TTABLE){ + int ret = lcurl_utils_apply_options(L, 1, 2, 1, p->err_mode, LCURL_ERROR_MULTI, CURLM_UNKNOWN_OPTION); + if(ret) return ret; + assert(lua_gettop(L) == 2); + } + return 1; } @@ -393,7 +405,18 @@ static int lcurl_multi_set_TIMERFUNCTION(lua_State *L){ static int lcurl_multi_setopt(lua_State *L){ lcurl_multi_t *p = lcurl_getmulti(L); - int opt = luaL_checklong(L, 2); + int opt; + + luaL_checkany(L, 2); + + if(lua_type(L, 2) == LUA_TTABLE){ + int ret = lcurl_utils_apply_options(L, 2, 1, 0, p->err_mode, LCURL_ERROR_MULTI, CURLM_UNKNOWN_OPTION); + if(ret) return ret; + lua_settop(L, 1); + return 1; + } + + opt = luaL_checklong(L, 2); lua_remove(L, 2); #define OPT_ENTRY(l, N, T, S) case CURLMOPT_##N: return lcurl_multi_set_##N(L); diff --git a/src/lcshare.c b/src/lcshare.c index e8a9fef..bf19572 100644 --- a/src/lcshare.c +++ b/src/lcshare.c @@ -11,11 +11,21 @@ static const char *LCURL_SHARE = LCURL_SHARE_NAME; //{ int lcurl_share_create(lua_State *L, int error_mode){ - lcurl_share_t *p = lutil_newudatap(L, lcurl_share_t, LCURL_SHARE); + lcurl_share_t *p; + + lua_settop(L, 1); + + p = lutil_newudatap(L, lcurl_share_t, LCURL_SHARE); p->curl = curl_share_init(); p->err_mode = error_mode; if(!p->curl) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_SHARE, CURLSHE_NOMEM); + if(lua_type(L, 1) == LUA_TTABLE){ + int ret = lcurl_utils_apply_options(L, 1, 2, 1, p->err_mode, LCURL_ERROR_SHARE, CURLSHE_BAD_OPTION); + if(ret) return ret; + assert(lua_gettop(L) == 2); + } + return 1; } @@ -70,7 +80,17 @@ static int lcurl_opt_set_long_(lua_State *L, int opt){ static int lcurl_share_setopt(lua_State *L){ lcurl_share_t *p = lcurl_getshare(L); - int opt = luaL_checklong(L, 2); + int opt; + + luaL_checkany(L, 2); + if(lua_type(L, 2) == LUA_TTABLE){ + int ret = lcurl_utils_apply_options(L, 2, 1, 0, p->err_mode, LCURL_ERROR_SHARE, CURLSHE_BAD_OPTION); + if(ret) return ret; + lua_settop(L, 1); + return 1; + } + + opt = luaL_checklong(L, 2); lua_remove(L, 2); #define OPT_ENTRY(l, N, T, S) case CURLSHOPT_##N: return lcurl_share_set_##N(L); diff --git a/src/lcutils.c b/src/lcutils.c index 379af27..de81346 100644 --- a/src/lcutils.c +++ b/src/lcutils.c @@ -133,3 +133,70 @@ int lcurl_util_pcall_method(lua_State *L, const char *name, int nargs, int nresu lua_insert(L, obj_index - 1); return lua_pcall(L, nargs + 1, nresults, errfunc); } + +static void lcurl_utils_pcall_close(lua_State *L, int obj){ + int top = lua_gettop(L); + lua_pushvalue(L, obj); + lcurl_util_pcall_method(L, "close", 0, 0, 0); + lua_settop(L, top); +} + +int lcurl_utils_apply_options(lua_State *L, int opt, int obj, int do_close, + int error_mode, int error_type, int error_code +){ + int top = lua_gettop(L); + opt = lua_absindex(L, opt); + obj = lua_absindex(L, obj); + + lua_pushnil(L); + while(lua_next(L, opt) != 0){ + int n; + assert(lua_gettop(L) == (top + 2)); + + if(lua_type(L, -2) == LUA_TNUMBER){ /* [curl.OPT_URL] = "http://localhost" */ + lua_pushvalue(L, -2); + lua_insert(L, -2); /*Stack : opt, obj, k, k, v */ + lua_pushliteral(L, "setopt"); /*Stack : opt, obj, k, k, v, "setopt" */ + n = 2; + } + else if(lua_type(L, -2) == LUA_TSTRING){ /* url = "http://localhost" */ + lua_pushliteral(L, "setopt_"); lua_pushvalue(L, -3); lua_concat(L, 2); + /*Stack : opt, obj, k, v, "setopt_XXX" */ + n = 1; + } + else{ + lua_pop(L, 1); + continue; + } + /*Stack : opt, obj, k,[ k,] v, `setoptXXX` */ + + lua_gettable(L, obj); /* get e["settop_XXX]*/ + + if(lua_isnil(L, -1)){ /* unknown option */ + if(do_close) lcurl_utils_pcall_close(L, obj); + lua_settop(L, top); + return lcurl_fail_ex(L, error_mode, error_type, error_code); + } + + lua_insert(L, -n-1); /*Stack : opt, obj, k, setoptXXX, [ k,] v */ + lua_pushvalue(L, obj); /*Stack : opt, obj, k, setoptXXX, [ k,] v, obj */ + lua_insert(L, -n-1); /*Stack : opt, obj, k, setoptXXX, obj, [ k,] v */ + + if(lua_pcall(L, n+1, 2, 0)){ + if(do_close) lcurl_utils_pcall_close(L, obj); + return lua_error(L); + } + + if(lua_isnil(L, -2)){ + if(do_close) lcurl_utils_pcall_close(L, obj); + lua_settop(L, top); + return 2; + } + + /*Stack : opt, obj, k, ok, nil*/ + lua_pop(L, 2); + assert(lua_gettop(L) == (top+1)); + } + assert(lua_gettop(L) == top); + return 0; +} diff --git a/src/lcutils.h b/src/lcutils.h index 7ae7143..1ef1e24 100644 --- a/src/lcutils.h +++ b/src/lcutils.h @@ -42,4 +42,7 @@ int lcurl_util_new_weak_table(lua_State*L, const char *mode); int lcurl_util_pcall_method(lua_State *L, const char *name, int nargs, int nresults, int errfunc); +int lcurl_utils_apply_options(lua_State *L, int opt, int obj, int do_close, + int error_mode, int error_type, int error_code + ); #endif diff --git a/test/test_safe.lua b/test/test_safe.lua index 82ae026..8e65d6f 100644 --- a/test/test_safe.lua +++ b/test/test_safe.lua @@ -104,7 +104,7 @@ function teardown() c = nil end -function test_error() +function test_easy_error() c = assert(curl.easy()) c:close() c = assert(curl.easy{ @@ -126,7 +126,7 @@ function test_error() end) end -function test_safe() +function test_easy_safe() c = assert(scurl.easy()) c:close() c = assert(scurl.easy{ @@ -149,6 +149,97 @@ function test_safe() end) end +function test_multi_error() + c = assert(curl.multi()) + c:close() + c = assert(curl.multi{ + maxconnects = 10; + [curl.OPT_MULTI_PIPELINING] = true, + }) + c:close() + + assert_error(function() + c = curl.multi{ + url_111 = "http://example.com", + } + end) + + assert_error(function() + c = curl.multi{ + maxconnects = "hello", + } + end) +end + +function test_multi_safe() + c = assert(scurl.multi()) + c:close() + c = assert(scurl.multi{ + maxconnects = 10; + [curl.OPT_MULTI_PIPELINING] = true, + }) + c:close() + + assert_pass(function() + c = scurl.multi{ + url_111 = "http://example.com", + } + end) + assert_nil(c) + + assert_error(function() + c = scurl.multi{ + maxconnects = "hello", + } + end) +end + +function test_share_error() + assert(curl.LOCK_DATA_COOKIE) + + c = assert(curl.share()) + c:close() + c = assert(curl.share{ + share = curl.LOCK_DATA_COOKIE; + }) + c:close() + + assert_error(function() + c = curl.share{ + url_111 = "http://example.com", + } + end) + + assert_error(function() + c = curl.share{ + share = "hello"; + } + end) +end + +function test_share_safe() + assert(curl.LOCK_DATA_COOKIE) + + c = assert(scurl.share()) + c:close() + c = assert(curl.share{ + share = scurl.LOCK_DATA_COOKIE; + }) + c:close() + + assert_pass(function() + c = scurl.share{ + url_111 = "http://example.com", + } + end) + + assert_error(function() + c = scurl.share{ + share = "hello"; + } + end) +end + end if not HAS_RUNNER then lunit.run() end