diff --git a/appveyor.yml b/appveyor.yml index e8959da..07dbc35 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ shallow_clone: true environment: LR_EXTERNAL: c:\external - CURL_VER: 7.62.0 + CURL_VER: 7.63.0 matrix: - LUA: "lua 5.1" diff --git a/src/lceasy.c b/src/lceasy.c index 620b157..52e88a8 100644 --- a/src/lceasy.c +++ b/src/lceasy.c @@ -16,6 +16,7 @@ #include "lcshare.h" #include "lcmulti.h" #include "lcmime.h" +#include "lcurlapi.h" #include static const char *LCURL_ERROR_TAG = "LCURL_ERROR_TAG"; @@ -82,6 +83,9 @@ int lcurl_easy_create(lua_State *L, int error_mode){ p->multi = NULL; #if LCURL_CURL_VER_GE(7,56,0) p->mime = NULL; +#endif +#if LCURL_CURL_VER_GE(7,63,0) + p->url = NULL; #endif p->storage = lcurl_storage_init(L); p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF; @@ -151,6 +155,10 @@ static int lcurl_easy_cleanup(lua_State *L){ p->mime = NULL; #endif +#if LCURL_CURL_VER_GE(7,63,0) + p->url = NULL; +#endif + if(p->storage != LUA_NOREF){ p->storage = lcurl_storage_free(L, p->storage); } @@ -539,6 +547,25 @@ static int lcurl_easy_set_MIMEPOST(lua_State *L){ #endif +#if LCURL_CURL_VER_GE(7,63,0) + +static int lcurl_easy_set_CURLU(lua_State *L) { + lcurl_easy_t *p = lcurl_geteasy(L); + lcurl_url_t *url = lcurl_geturl_at(L, 2); + CURLcode code = curl_easy_setopt(p->curl, CURLOPT_CURLU, url->url); + if (code != CURLE_OK) { + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); + } + + lcurl_storage_preserve_iv(L, p->storage, CURLOPT_CURLU, 2); + + p->url = url; + + lua_settop(L, 1); + return 1; +} + +#endif //} //{ unset @@ -907,6 +934,25 @@ static int lcurl_easy_unset_MIMEPOST(lua_State *L){ #endif +#if LCURL_CURL_VER_GE(7,63,0) + +static int lcurl_easy_unset_CURLU(lua_State *L) { + lcurl_easy_t *p = lcurl_geteasy(L); + CURLcode code = curl_easy_setopt(p->curl, CURLOPT_CURLU, NULL); + if (code != CURLE_OK) { + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); + } + + lcurl_storage_remove_i(L, p->storage, CURLOPT_CURLU); + + p->url = NULL; + + lua_settop(L, 1); + return 1; +} + +#endif + //} //} @@ -1731,6 +1777,9 @@ static const struct luaL_Reg lcurl_easy_methods[] = { #if LCURL_CURL_VER_GE(7,56,0) OPT_ENTRY(mimepost, MIMEPOST, TTT, 0, 0) #endif +#if LCURL_CURL_VER_GE(7,63,0) + OPT_ENTRY(curlu, CURLU, TTT, 0, 0) +#endif #undef OPT_ENTRY #define OPT_ENTRY(L, N, T, S, D) { "unsetopt_"#L, lcurl_easy_unset_##N }, @@ -1756,6 +1805,9 @@ static const struct luaL_Reg lcurl_easy_methods[] = { #if LCURL_CURL_VER_GE(7,56,0) OPT_ENTRY(mimepost, MIMEPOST, TTT, 0, 0) #endif +#if LCURL_CURL_VER_GE(7,63,0) + OPT_ENTRY(curlu, CURLU, TTT, 0, 0) +#endif #undef OPT_ENTRY #define OPT_ENTRY(L, N, T, S) { "getinfo_"#L, lcurl_easy_get_##N }, @@ -1813,6 +1865,9 @@ static const lcurl_const_t lcurl_easy_opt[] = { #if LCURL_CURL_VER_GE(7,56,0) OPT_ENTRY(mimepost, MIMEPOST, TTT, 0, 0) #endif +#if LCURL_CURL_VER_GE(7,63,0) + OPT_ENTRY(curlu, CURLU, TTT, 0, 0) +#endif #undef OPT_ENTRY #undef FLG_ENTRY diff --git a/src/lceasy.h b/src/lceasy.h index 7c95668..e4d3776 100644 --- a/src/lceasy.h +++ b/src/lceasy.h @@ -38,17 +38,24 @@ enum { #define LCURL_EASY_MAGIC 0xEA #if LCURL_CC_SUPPORT_FORWARD_TYPEDEF -typedef struct lcurl_multi_tag lcurl_multi_t; -#if LCURL_CURL_VER_GE(7,56,0) -typedef struct lcurl_mime_tag lcurl_mime_t; -#endif + typedef struct lcurl_multi_tag lcurl_multi_t; + #if LCURL_CURL_VER_GE(7,56,0) + typedef struct lcurl_mime_tag lcurl_mime_t; + #endif + #if LCURL_CURL_VER_GE(7,63,0) + typedef struct lcurl_url_tag lcurl_url_t; + #endif #else -struct lcurl_multi_tag; -#define lcurl_multi_t struct lcurl_multi_tag -#if LCURL_CURL_VER_GE(7,56,0) -struct lcurl_mime_tag; -#define lcurl_mime_t struct lcurl_mime_tag -#endif + struct lcurl_multi_tag; + #define lcurl_multi_t struct lcurl_multi_tag + #if LCURL_CURL_VER_GE(7,56,0) + struct lcurl_mime_tag; + #define lcurl_mime_t struct lcurl_mime_tag + #endif + #if LCURL_CURL_VER_GE(7,63,0) + struct lcurl_url_tag; + #define lcurl_url_t struct lcurl_url_tag + #endif #endif typedef struct lcurl_easy_tag{ @@ -66,6 +73,10 @@ typedef struct lcurl_easy_tag{ lcurl_mime_t *mime; #endif +#if LCURL_CURL_VER_GE(7,63,0) + lcurl_url_t *url; +#endif + CURL *curl; int storage; int lists[LCURL_LIST_COUNT]; diff --git a/src/lcopteasy.h b/src/lcopteasy.h index 225bea5..166b07d 100644 --- a/src/lcopteasy.h +++ b/src/lcopteasy.h @@ -441,7 +441,7 @@ OPT_ENTRY( timevalue_large, TIMEVALUE_LARGE ,OFF, 0, LCURL_DEF #if LCURL_CURL_VER_GE(7,60,0) OPT_ENTRY(dns_shuffle_addresses, DNS_SHUFFLE_ADDRESSES, LNG, 0, LCURL_DEFAULT_VALUE) -OPT_ENTRY(haproxyprotocol, HAPROXYPROTOCOL, LNG, 0, LCURL_DEFAULT_VALUE) +OPT_ENTRY(haproxyprotocol, HAPROXYPROTOCOL, LNG, 0, LCURL_DEFAULT_VALUE) #endif #if LCURL_CURL_VER_GE(7,61,0) diff --git a/src/lcurlapi.c b/src/lcurlapi.c index a0f5f51..edbffa8 100644 --- a/src/lcurlapi.c +++ b/src/lcurlapi.c @@ -21,12 +21,6 @@ static const char *LCURL_URL = LCURL_URL_NAME; #define lcurl_geturl(L) lcurl_geturl_at(L, 1) -typedef struct lcurl_url_tag{ - CURLU *url; - - int err_mode; -}lcurl_url_t; - int lcurl_url_create(lua_State *L, int error_mode){ lcurl_url_t *p; @@ -55,7 +49,7 @@ int lcurl_url_create(lua_State *L, int error_mode){ return 1; } -static lcurl_url_t *lcurl_geturl_at(lua_State *L, int i){ +lcurl_url_t *lcurl_geturl_at(lua_State *L, int i){ lcurl_url_t *p = (lcurl_url_t *)lutil_checkudatap (L, i, LCURL_URL); luaL_argcheck (L, p != NULL, 1, LCURL_URL_NAME" object expected"); return p; diff --git a/src/lcurlapi.h b/src/lcurlapi.h index bdf358b..58b4efd 100644 --- a/src/lcurlapi.h +++ b/src/lcurlapi.h @@ -17,6 +17,18 @@ void lcurl_url_initlib(lua_State *L, int nup); +#if LCURL_CURL_VER_GE(7,62,0) + +typedef struct lcurl_url_tag { + CURLU *url; + + int err_mode; +}lcurl_url_t; + int lcurl_url_create(lua_State *L, int error_mode); +lcurl_url_t *lcurl_geturl_at(lua_State *L, int i); + +#endif + #endif \ No newline at end of file diff --git a/test/test_curl.lua b/test/test_curl.lua index ca7d806..ce6a44a 100644 --- a/test/test_curl.lua +++ b/test/test_curl.lua @@ -20,20 +20,11 @@ local fname = "./test.download" local utils = require "utils" -local is_curl_ge = utils.is_curl_ge - -local function weak_ptr(val) - return setmetatable({value = val},{__mode = 'v'}) -end - -local function gc_collect() - for i = 1, 5 do - collectgarbage("collect") - end -end +local weak_ptr, gc_collect, is_curl_ge, is_curl_eq, read_file, stream, Stream, dump_request = + utils.import('weak_ptr', 'gc_collect', 'is_curl_ge', 'is_curl_eq', 'read_file', 'stream', 'Stream', 'dump_request') -- Bug. libcurl 7.56.0 does not add `Content-Type: text/plain` -local text_plain = utils.is_curl_eq(7,56,0) and 'test/plain' or 'text/plain' +local text_plain = is_curl_eq(7,56,0) and 'test/plain' or 'text/plain' local GET_URL = "http://127.0.0.1:7090/get" diff --git a/test/test_urlapi.lua b/test/test_urlapi.lua index bbba08b..ff0ab82 100644 --- a/test/test_urlapi.lua +++ b/test/test_urlapi.lua @@ -15,6 +15,12 @@ local skip = lunit.skip or function() end local curl = require "cURL" local scurl = require "cURL.safe" local utils = require "utils" +local json = require "dkjson" +local table = table + +local weak_ptr, gc_collect, is_curl_eq = utils.import('weak_ptr', 'gc_collect', 'is_curl_eq') + +local GET_URL = "http://127.0.0.1:7090/get" local tostring, pcall = tostring, pcall @@ -150,7 +156,11 @@ end) it('should append only one parameter in query per call', function() url = U"http://example.com" assert_equal(url, url:set_query("a=hello world&b=A&B", curl.U_APPENDQUERY + curl.U_URLENCODE)) - assert_equal("http://example.com/?a=hello+world%26b=A%26B", url:get_url()) + if is_curl_eq(7, 62, 0) then + assert_equal("http://example.com/?a=hello+world%26b=A%26B", url:get_url()) + else + assert_equal("http://example.com/?a=hello+world%26b%3dA%26B", url:get_url()) + end end) it('should set encoded query', function() @@ -203,4 +213,87 @@ end) end end +local _ENV = TEST_CASE'curlu parameter' if ENABLE then + +if not curl.OPT_CURLU then test = skip_case('CURLU option avaliable since libcurl 7.63.0') else + +local it = setmetatable(_ENV or _M, {__call = function(self, describe, fn) + self["test " .. describe] = fn +end}) + +local url, easy, buffer + +local function writer(chunk) + table.insert(buffer, chunk) +end + +local function json_data() + return json.decode(table.concat(buffer)) +end + +local function U(u) + url = assert_userdata(curl.url()) + assert_equal(url, url:set_url(u)) + return url +end + +function setup() + buffer = {} +end + +function teardown() + if url then url:cleanup() end + if easy then easy:close() end + url = nil +end + +it('easy should prevent url from gc', function() + local purl + do + easy = curl.easy() + local url = U(GET_URL) + assert_equal(easy, easy:setopt_curlu(url)) + purl = weak_ptr(url) + end + + gc_collect() + assert_not_nil(purl.value) + + assert_equal(easy, easy:unsetopt_curlu()) + + gc_collect() + assert_not_nil(purl.value) +end) + +it('should use url from curlu parameter', function() + url = U(GET_URL) + easy = curl.easy {curlu = url, writefunction = writer} + assert_equal(easy, easy:perform()) + local response = assert_table(json_data()) + assert_equal(GET_URL, response.url) +end) + +it('should be possible reset url', function() + url = U("http://example.com") + easy = curl.easy {curlu = url, writefunction = writer} + url:set_url(GET_URL) + + assert_equal(easy, easy:perform()) + local response = assert_table(json_data()) + assert_equal(GET_URL, response.url) +end) + +it('should be possible reuse url', function() + url = U(GET_URL) + for i = 1, 5 do + local easy = curl.easy {curlu = url, writefunction = writer} + assert_equal(easy, easy:perform()) + local response = assert_table(json_data()) + assert_equal(GET_URL, response.url) + gc_collect() + end +end) + +end end + RUN() diff --git a/test/utils.lua b/test/utils.lua index bc50ca9..0f81751 100644 --- a/test/utils.lua +++ b/test/utils.lua @@ -4,9 +4,10 @@ local function weak_ptr(val) return setmetatable({value = val},{__mode = 'v'}) end -local function gc_collect() - collectgarbage("collect") - collectgarbage("collect") +local function gc_collect(n) + for i = 1, (n or 2) do + collectgarbage("collect") + end end local function cver(min, maj, pat)