diff --git a/src/lceasy.c b/src/lceasy.c index 0b0fc4a..e543675 100644 --- a/src/lceasy.c +++ b/src/lceasy.c @@ -97,6 +97,9 @@ int lcurl_easy_create(lua_State *L, int error_mode){ p->match.cb_ref = p->match.ud_ref = LUA_NOREF; p->chunk_bgn.cb_ref = p->chunk_bgn.ud_ref = LUA_NOREF; p->chunk_end.cb_ref = p->chunk_end.ud_ref = LUA_NOREF; +#if LCURL_CURL_VER_GE(7,64,0) + p->trailer.cb_ref = p->trailer.ud_ref = LUA_NOREF; +#endif p->rbuffer.ref = LUA_NOREF; for(i = 0; i < LCURL_LIST_COUNT; ++i){ p->lists[i] = LUA_NOREF; @@ -179,10 +182,14 @@ static int lcurl_easy_cleanup(lua_State *L){ luaL_unref(L, LCURL_LUA_REGISTRY, p->chunk_bgn.ud_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->chunk_end.cb_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->chunk_end.ud_ref); +#if LCURL_CURL_VER_GE(7,64,0) + luaL_unref(L, LCURL_LUA_REGISTRY, p->trailer.cb_ref); + luaL_unref(L, LCURL_LUA_REGISTRY, p->trailer.ud_ref); +#endif luaL_unref(L, LCURL_LUA_REGISTRY, p->hd.cb_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->hd.ud_ref); luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref); - + p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF; p->rd.cb_ref = p->rd.ud_ref = LUA_NOREF; p->hd.cb_ref = p->hd.ud_ref = LUA_NOREF; @@ -192,6 +199,9 @@ static int lcurl_easy_cleanup(lua_State *L){ p->match.cb_ref = p->match.ud_ref = LUA_NOREF; p->chunk_bgn.cb_ref = p->chunk_bgn.ud_ref = LUA_NOREF; p->chunk_end.cb_ref = p->chunk_end.ud_ref = LUA_NOREF; +#if LCURL_CURL_VER_GE(7,64,0) + p->trailer.cb_ref = p->trailer.ud_ref = LUA_NOREF; +#endif p->rbuffer.ref = LUA_NOREF; for(i = 0; i < LCURL_LIST_COUNT; ++i){ @@ -324,10 +334,12 @@ static int lcurl_opt_set_long_(lua_State *L, int opt){ if(lua_isboolean(L, 2)){ val = lua_toboolean(L, 2); if( val - && (opt == CURLOPT_SSL_VERIFYHOST) + && ( + (opt == CURLOPT_SSL_VERIFYHOST) #if LCURL_CURL_VER_GE(7,52,0) - && (opt == CURLOPT_PROXY_SSL_VERIFYHOST) + || (opt == CURLOPT_PROXY_SSL_VERIFYHOST) #endif + ) ){ val = 2; } @@ -566,6 +578,7 @@ static int lcurl_easy_set_CURLU(lua_State *L) { } #endif + //} //{ unset @@ -953,6 +966,27 @@ static int lcurl_easy_unset_CURLU(lua_State *L) { #endif +#if LCURL_CURL_VER_GE(7,64,0) + +static int lcurl_easy_unset_TRAILERFUNCTION(lua_State *L){ + lcurl_easy_t *p = lcurl_geteasy(L); + + CURLcode code = curl_easy_setopt(p->curl, CURLOPT_TRAILERFUNCTION, NULL); + if(code != CURLE_OK){ + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code); + } + curl_easy_setopt(p->curl, CURLOPT_TRAILERDATA, NULL); + + luaL_unref(L, LCURL_LUA_REGISTRY, p->trailer.cb_ref); + luaL_unref(L, LCURL_LUA_REGISTRY, p->trailer.ud_ref); + p->trailer.cb_ref = p->trailer.ud_ref = LUA_NOREF; + + lua_settop(L, 1); + return 1; +} + +#endif + //} //} @@ -1618,6 +1652,70 @@ static int lcurl_easy_set_CHUNK_END_FUNCTION(lua_State *L){ //} +//{ Trailer + +#if LCURL_CURL_VER_GE(7,64,0) + +static int lcurl_trailer_callback(struct curl_slist **list, void *arg) { + lcurl_easy_t *p = arg; + lua_State *L = p->L; + int top = lua_gettop(L); + int n = lcurl_util_push_cb(L, &p->trailer); + + if (lua_pcall(L, n - 1, LUA_MULTRET, 0)) { + assert(lua_gettop(L) >= top); + lua_pushlightuserdata(L, (void*)LCURL_ERROR_TAG); + lua_insert(L, top + 1); + return CURL_TRAILERFUNC_ABORT; + } + + n = lua_gettop(L); + + if (n == top) { + return CURL_TRAILERFUNC_OK; + } + + /* libcurl will free the list */ + *list = lcurl_util_to_slist(L, top + 1); + if (*list) { + lua_settop(L, top); + return CURL_TRAILERFUNC_OK; + } + + // empty array or NULL + if (lua_istable(L, top + 1) || lutil_is_null(L, top + 1)) { + lua_settop(L, top); + return CURL_TRAILERFUNC_OK; + } + + // true + if((lua_type(L, top + 1) == LUA_TBOOLEAN) && (lua_toboolean(L, top + 1))){ + lua_settop(L, top); + return CURL_TRAILERFUNC_OK; + } + + // single nil + if((n == (top + 1)) && lua_isnil(L, top + 1)){ + lua_settop(L, top); + return CURL_TRAILERFUNC_OK; + } + + lua_settop(L, top); + return CURL_TRAILERFUNC_ABORT; +} + +static int lcurl_easy_set_TRAILERFUNCTION (lua_State *L){ + lcurl_easy_t *p = lcurl_geteasy(L); + return lcurl_easy_set_callback(L, p, &p->trailer, + CURLOPT_TRAILERFUNCTION, CURLOPT_TRAILERDATA, + "trailer", lcurl_trailer_callback + ); +} + +#endif + +//} + //} static int lcurl_easy_setopt(lua_State *L){ @@ -1780,6 +1878,9 @@ static const struct luaL_Reg lcurl_easy_methods[] = { #if LCURL_CURL_VER_GE(7,63,0) OPT_ENTRY(curlu, CURLU, TTT, 0, 0) #endif +#if LCURL_CURL_VER_GE(7,64,0) + OPT_ENTRY(trailerfunction, TRAILERFUNCTION, TTT, 0, 0) +#endif #undef OPT_ENTRY #define OPT_ENTRY(L, N, T, S, D) { "unsetopt_"#L, lcurl_easy_unset_##N }, @@ -1808,6 +1909,9 @@ static const struct luaL_Reg lcurl_easy_methods[] = { #if LCURL_CURL_VER_GE(7,63,0) OPT_ENTRY(curlu, CURLU, TTT, 0, 0) #endif +#if LCURL_CURL_VER_GE(7,64,0) + OPT_ENTRY(trailerfunction, TRAILERFUNCTION, TTT, 0, 0) +#endif #undef OPT_ENTRY #define OPT_ENTRY(L, N, T, S) { "getinfo_"#L, lcurl_easy_get_##N }, @@ -1868,6 +1972,9 @@ static const lcurl_const_t lcurl_easy_opt[] = { #if LCURL_CURL_VER_GE(7,63,0) OPT_ENTRY(curlu, CURLU, TTT, 0, 0) #endif +#if LCURL_CURL_VER_GE(7,64,0) + OPT_ENTRY(trailerfunction, TRAILERFUNCTION, TTT, 0, 0) +#endif #undef OPT_ENTRY #undef FLG_ENTRY diff --git a/src/lceasy.h b/src/lceasy.h index 3c244ee..9050add 100644 --- a/src/lceasy.h +++ b/src/lceasy.h @@ -89,6 +89,9 @@ typedef struct lcurl_easy_tag{ lcurl_callback_t match; lcurl_callback_t chunk_bgn; lcurl_callback_t chunk_end; +#if LCURL_CURL_VER_GE(7,64,0) + lcurl_callback_t trailer; +#endif }lcurl_easy_t; int lcurl_easy_create(lua_State *L, int error_mode); @@ -111,6 +114,9 @@ size_t lcurl_read_callback(lua_State *L, #ifdef lcurl_mime_t #undef lcurl_mime_t #endif +#ifdef lcurl_url_t +#undef lcurl_url_t +#endif #endif #endif diff --git a/src/lcopteasy.h b/src/lcopteasy.h index 6e0940f..9d6282f 100644 --- a/src/lcopteasy.h +++ b/src/lcopteasy.h @@ -461,6 +461,10 @@ OPT_ENTRY(doh_url, DOH_URL, STR, 0, LCURL_DEFA OPT_ENTRY(upload_buffersize, UPLOAD_BUFFERSIZE, LNG, 0, 64 * 1024) #endif +#if LCURL_CURL_VER_GE(7,64,0) +OPT_ENTRY(http09_allowed, HTTP09_ALLOWED, LNG, 0, 0) +#endif + #if LCURL_CURL_VER_GE(7,65,0) OPT_ENTRY(maxage_conn, MAXAGE_CONN, LNG, 0, LCURL_DEFAULT_VALUE) #endif diff --git a/test/test_easy.lua b/test/test_easy.lua index be9e08f..92d7dcf 100644 --- a/test/test_easy.lua +++ b/test/test_easy.lua @@ -18,7 +18,6 @@ local json = require "dkjson" local path = require "path" local upath = require "path".new('/') local utils = require "utils" --- local url = "http://127.0.0.1:7090/get" local fname = "./test.download" -- local GET_URL = "http://example.com" @@ -1164,4 +1163,110 @@ end end +local _ENV = TEST_CASE'trailer_callback' if ENABLE and is_curl_ge(7,64,0) then + +local url = POST_URL + +local m, c, t + +local function json_data() + return json.decode(table.concat(t)) +end + +local treader = function(t) + local i = 0 + return function() + i = i + 1 + return t[i] + end +end + +function setup() + t = {} + c = assert(scurl.easy{ + url = url, + post = true, + httpheader = {"Transfer-Encoding: chunked"}, + readfunction = treader {'a=1&', 'b=2&'}, + timeout = 60, + }) + assert_equal(c, c:setopt_writefunction(table.insert, t)) +end + +function teardown() + if c then c:close() end + if m then m:close() end + t, c, m = nil +end + +local empty_responses = { + {'no_response', function() end}, + {'nil_response', function() return nil end}, + {'null_response', function() return curl.null end}, + {'true_response', function() return true end}, + {'empty_array', function() return {} end}, +} + +local abort_responses = { + {'false_response', function() return false end}, + {'nil_with_error_response', function() return nil, 'error message' end}, + {'numeric_response_0', function() return 0 end}, + {'numeric_response_1', function() return 1 end}, +} + +for _, response in ipairs(empty_responses) do + _ENV[ 'test_' .. response[1] ] = function() + local trailer_called = 0 + assert_equal(c, c:setopt_trailerfunction(function() + trailer_called = trailer_called + 1 + return response[2]() + end)) + + assert_equal(c, c:perform()) + + assert_equal(1, trailer_called) + + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + + assert_equal('1', data.form.a) + assert_equal('2', data.form.b) + end +end + +for _, response in ipairs(abort_responses) do + _ENV[ 'test_' .. response[1] ] = function() + local trailer_called = 0 + assert_equal(c, c:setopt_trailerfunction(function() + trailer_called = trailer_called + 1 + return response[2]() + end)) + + local ok, err = assert_nil(c:perform()) + assert_equal(1, trailer_called) + assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), err) + end +end + +function test_send_header() + local trailer_called = 0 + assert_equal(c, c:setopt_trailerfunction(function() + trailer_called = trailer_called + 1 + return {'x-trailer-header: value'} + end)) + + assert_equal(c, c:perform()) + + assert_equal(1, trailer_called) + + assert_equal(200, c:getinfo_response_code()) + local data = assert_table(json_data()) + + assert_equal('1', data.form.a) + assert_equal('2', data.form.b) + assert_equal('value', data.headers['x-trailer-header']) +end + +end + RUN()