From 144ceeb123d1ef8cf8008787a7f7d6b2292c8f23 Mon Sep 17 00:00:00 2001 From: Alexey Melnichuk Date: Mon, 1 Sep 2014 13:38:34 +0500 Subject: [PATCH] Change. Easy ctor and `setopt` method could use table to set multiple options. ```Lua c = curl.easy{ url = 'http://example.com', [curl.OPT_VERBOSE] = true, } ``` --- doc/lcurl.ldoc | 14 +++++- src/lceasy.c | 117 ++++++++++++++++++++++++++++++++++++++------- src/lcutils.c | 7 +++ src/lcutils.h | 2 + test/test_safe.lua | 68 +++++++++++++++++++++++++- 5 files changed, 190 insertions(+), 18 deletions(-) diff --git a/doc/lcurl.ldoc b/doc/lcurl.ldoc index 151b12d..e7016b9 100644 --- a/doc/lcurl.ldoc +++ b/doc/lcurl.ldoc @@ -9,7 +9,15 @@ function form() end --- Create Easy object -- +-- @tparam[opt] table options -- @treturn[1] easy new curl easy object +-- +-- @usage +-- c = curl.easy{ +-- url = 'http://example.com', +-- [curl.OPT_VERBOSE] = true, +-- } +-- function easy() end --- Create Multi object @@ -187,7 +195,7 @@ function close() end --- Set options. -- --- @tparam number opt one of `curl.OPT_XXX` constant +-- @tparam number|table opt one of `curl.OPT_XXX` constant or options table -- @param ... value -- @treturn easy self -- @@ -197,6 +205,10 @@ function close() end -- function(t, n) return table.remove(t) end, -- {"1111", "2222"} -- ) +--c:setopt{ +-- url = 'http://example.com', +-- [curl.OPT_VERBOSE] = true, +-- } function setopt() end --- Get information. diff --git a/src/lceasy.c b/src/lceasy.c index 7d0b6d2..88ef621 100644 --- a/src/lceasy.c +++ b/src/lceasy.c @@ -11,12 +11,92 @@ static const char *LCURL_ERROR_TAG = "LCURL_ERROR_TAG"; #define LCURL_EASY_NAME LCURL_PREFIX" Easy" static const char *LCURL_EASY = LCURL_EASY_NAME; +#if LCURL_CURL_VER_GE(7,21,5) +# define LCURL_E_UNKNOWN_OPTION CURLE_UNKNOWN_OPTION +#else +# define LCURL_E_UNKNOWN_OPTION CURLE_UNKNOWN_TELNET_OPTION +#endif + //{ +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 = lutil_newudatap(L, lcurl_easy_t, LCURL_EASY); + lcurl_easy_t *p; int i; + + lua_settop(L, 1); /* options */ + + p = lutil_newudatap(L, lcurl_easy_t, LCURL_EASY); + p->curl = curl_easy_init(); + p->err_mode = error_mode; if(!p->curl) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_FAILED_INIT); p->L = L; @@ -29,6 +109,13 @@ int lcurl_easy_create(lua_State *L, int error_mode){ for(i = 0; i < LCURL_LIST_COUNT; ++i){ p->lists[i] = LUA_NOREF; } + + if(lua_type(L, 1) == LUA_TTABLE){ + int ret = lcurl_easy_apply_options(L, p, 1, 2, 1); + if(ret) return ret; + assert(lua_gettop(L) == 2); + } + return 1; } @@ -642,7 +729,17 @@ static int lcurl_easy_set_PROGRESSFUNCTION(lua_State *L){ static int lcurl_easy_setopt(lua_State *L){ lcurl_easy_t *p = lcurl_geteasy(L); - int opt = luaL_checklong(L, 2); + long opt; + + luaL_checkany(L, 2); + if(lua_type(L, 2) == LUA_TTABLE){ + int ret = lcurl_easy_apply_options(L, p, 2, 1, 0); + 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 CURLOPT_##N: return lcurl_easy_set_##N(L); @@ -658,13 +755,7 @@ static int lcurl_easy_setopt(lua_State *L){ } #undef OPT_ENTRY - return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, -#if LCURL_CURL_VER_GE(7,21,5) - CURLE_UNKNOWN_OPTION -#else - CURLE_UNKNOWN_TELNET_OPTION -#endif - ); + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, LCURL_E_UNKNOWN_OPTION); } static int lcurl_easy_getinfo(lua_State *L){ @@ -678,13 +769,7 @@ static int lcurl_easy_getinfo(lua_State *L){ } #undef OPT_ENTRY - return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, -#if LCURL_CURL_VER_GE(7,21,5) - CURLE_UNKNOWN_OPTION -#else - CURLE_UNKNOWN_TELNET_OPTION -#endif - ); + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, LCURL_E_UNKNOWN_OPTION); } //} diff --git a/src/lcutils.c b/src/lcutils.c index 331824d..379af27 100644 --- a/src/lcutils.c +++ b/src/lcutils.c @@ -126,3 +126,10 @@ int lcurl_util_new_weak_table(lua_State*L, const char *mode){ assert((top+1) == lua_gettop(L)); return 1; } + +int lcurl_util_pcall_method(lua_State *L, const char *name, int nargs, int nresults, int errfunc){ + int obj_index = -nargs - 1; + lua_getfield(L, obj_index, name); + lua_insert(L, obj_index - 1); + return lua_pcall(L, nargs + 1, nresults, errfunc); +} diff --git a/src/lcutils.h b/src/lcutils.h index 468be79..7ae7143 100644 --- a/src/lcutils.h +++ b/src/lcutils.h @@ -40,4 +40,6 @@ int lcurl_util_push_cb(lua_State *L, lcurl_callback_t *c); 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); + #endif diff --git a/test/test_safe.lua b/test/test_safe.lua index b0facaf..82ae026 100644 --- a/test/test_safe.lua +++ b/test/test_safe.lua @@ -30,10 +30,11 @@ end local _ENV = TEST_CASE'setopt' do +local curl = require "lcurl.safe" local c function setup() - c = assert(require"lcurl.safe".easy()) + c = assert(curl.easy()) end function teardown() @@ -63,6 +64,13 @@ function test_array() assert_equal(c, c:setopt_httpheader{"k:v"}) end +function test_multiple_options() + assert_error(function() c:setopt{verbose = "false"} end) + assert_error(function() c:setopt{verbose = "1"} end) + assert_equal(c, c:setopt{verbose = false}) + assert_equal(c, c:setopt{[curl.OPT_VERBOSE] = false}) +end + end local _ENV = TEST_CASE'error_object' do @@ -85,4 +93,62 @@ end end +local _ENV = TEST_CASE'ctor' do + +local scurl = require "lcurl.safe" +local curl = require "lcurl" +local c + +function teardown() + if c then c:close() end + c = nil +end + +function test_error() + c = assert(curl.easy()) + c:close() + c = assert(curl.easy{ + url = "http://example.com", + [curl.OPT_VERBOSE] = true, + }) + c:close() + + assert_error(function() + c = curl.easy{ + url_111 = "http://example.com", + } + end) + + assert_error(function() + c = curl.easy{ + url = 123, + } + end) +end + +function test_safe() + c = assert(scurl.easy()) + c:close() + c = assert(scurl.easy{ + url = "http://example.com", + [curl.OPT_VERBOSE] = true, + }) + c:close() + + assert_pass(function() + c = scurl.easy{ + url_111 = "http://example.com", + } + end) + assert_nil(c) + + assert_error(function() + c = scurl.easy{ + url = 123, + } + end) +end + +end + if not HAS_RUNNER then lunit.run() end