Skip to content

Commit e70f6ac

Browse files
committed
Add. Support CURLOPT_TRAILERFUNCTION
1 parent e0b1d2e commit e70f6ac

File tree

4 files changed

+216
-3
lines changed

4 files changed

+216
-3
lines changed

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ shallow_clone: true
77

88
environment:
99
LR_EXTERNAL: c:\external
10-
CURL_VER: 7.63.0
10+
CURL_VER: 7.64.0
1111

1212
matrix:
1313
- LUA: "lua 5.1"

src/lceasy.c

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ int lcurl_easy_create(lua_State *L, int error_mode){
9797
p->match.cb_ref = p->match.ud_ref = LUA_NOREF;
9898
p->chunk_bgn.cb_ref = p->chunk_bgn.ud_ref = LUA_NOREF;
9999
p->chunk_end.cb_ref = p->chunk_end.ud_ref = LUA_NOREF;
100+
#if LCURL_CURL_VER_GE(7,64,0)
101+
p->trailer.cb_ref = p->trailer.ud_ref = LUA_NOREF;
102+
#endif
100103
p->rbuffer.ref = LUA_NOREF;
101104
for(i = 0; i < LCURL_LIST_COUNT; ++i){
102105
p->lists[i] = LUA_NOREF;
@@ -179,10 +182,14 @@ static int lcurl_easy_cleanup(lua_State *L){
179182
luaL_unref(L, LCURL_LUA_REGISTRY, p->chunk_bgn.ud_ref);
180183
luaL_unref(L, LCURL_LUA_REGISTRY, p->chunk_end.cb_ref);
181184
luaL_unref(L, LCURL_LUA_REGISTRY, p->chunk_end.ud_ref);
185+
#if LCURL_CURL_VER_GE(7,64,0)
186+
luaL_unref(L, LCURL_LUA_REGISTRY, p->trailer.cb_ref);
187+
luaL_unref(L, LCURL_LUA_REGISTRY, p->trailer.ud_ref);
188+
#endif
182189
luaL_unref(L, LCURL_LUA_REGISTRY, p->hd.cb_ref);
183190
luaL_unref(L, LCURL_LUA_REGISTRY, p->hd.ud_ref);
184191
luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref);
185-
192+
186193
p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF;
187194
p->rd.cb_ref = p->rd.ud_ref = LUA_NOREF;
188195
p->hd.cb_ref = p->hd.ud_ref = LUA_NOREF;
@@ -192,6 +199,9 @@ static int lcurl_easy_cleanup(lua_State *L){
192199
p->match.cb_ref = p->match.ud_ref = LUA_NOREF;
193200
p->chunk_bgn.cb_ref = p->chunk_bgn.ud_ref = LUA_NOREF;
194201
p->chunk_end.cb_ref = p->chunk_end.ud_ref = LUA_NOREF;
202+
#if LCURL_CURL_VER_GE(7,64,0)
203+
p->trailer.cb_ref = p->trailer.ud_ref = LUA_NOREF;
204+
#endif
195205
p->rbuffer.ref = LUA_NOREF;
196206

197207
for(i = 0; i < LCURL_LIST_COUNT; ++i){
@@ -566,6 +576,7 @@ static int lcurl_easy_set_CURLU(lua_State *L) {
566576
}
567577

568578
#endif
579+
569580
//}
570581

571582
//{ unset
@@ -953,6 +964,27 @@ static int lcurl_easy_unset_CURLU(lua_State *L) {
953964

954965
#endif
955966

967+
#if LCURL_CURL_VER_GE(7,64,0)
968+
969+
static int lcurl_easy_unset_TRAILERFUNCTION(lua_State *L){
970+
lcurl_easy_t *p = lcurl_geteasy(L);
971+
972+
CURLcode code = curl_easy_setopt(p->curl, CURLOPT_TRAILERFUNCTION, NULL);
973+
if(code != CURLE_OK){
974+
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
975+
}
976+
curl_easy_setopt(p->curl, CURLOPT_TRAILERFUNCTION, NULL);
977+
978+
luaL_unref(L, LCURL_LUA_REGISTRY, p->trailer.cb_ref);
979+
luaL_unref(L, LCURL_LUA_REGISTRY, p->trailer.ud_ref);
980+
p->trailer.cb_ref = p->trailer.ud_ref = LUA_NOREF;
981+
982+
lua_settop(L, 1);
983+
return 1;
984+
}
985+
986+
#endif
987+
956988
//}
957989

958990
//}
@@ -1618,6 +1650,70 @@ static int lcurl_easy_set_CHUNK_END_FUNCTION(lua_State *L){
16181650

16191651
//}
16201652

1653+
//{ Trailer
1654+
1655+
#if LCURL_CURL_VER_GE(7,64,0)
1656+
1657+
static int lcurl_trailer_callback(struct curl_slist **list, void *arg) {
1658+
lcurl_easy_t *p = arg;
1659+
lua_State *L = p->L;
1660+
int top = lua_gettop(L);
1661+
int n = lcurl_util_push_cb(L, &p->trailer);
1662+
1663+
if (lua_pcall(L, n - 1, LUA_MULTRET, 0)) {
1664+
assert(lua_gettop(L) >= top);
1665+
lua_pushlightuserdata(L, (void*)LCURL_ERROR_TAG);
1666+
lua_insert(L, top + 1);
1667+
return CURL_TRAILERFUNC_ABORT;
1668+
}
1669+
1670+
n = lua_gettop(L);
1671+
1672+
if (n == top) {
1673+
return CURL_TRAILERFUNC_OK;
1674+
}
1675+
1676+
/* libcurl will free the list */
1677+
*list = lcurl_util_to_slist(L, top + 1);
1678+
if (*list) {
1679+
lua_settop(L, top);
1680+
return CURL_TRAILERFUNC_OK;
1681+
}
1682+
1683+
// empty array or NULL
1684+
if (lua_istable(L, top + 1) || lutil_is_null(L, top + 1)) {
1685+
lua_settop(L, top);
1686+
return CURL_TRAILERFUNC_OK;
1687+
}
1688+
1689+
// true
1690+
if((lua_type(L, top + 1) == LUA_TBOOLEAN) && (lua_toboolean(L, top + 1))){
1691+
lua_settop(L, top);
1692+
return CURL_TRAILERFUNC_OK;
1693+
}
1694+
1695+
// single nil
1696+
if((n == (top + 1)) && lua_isnil(L, top + 1)){
1697+
lua_settop(L, top);
1698+
return CURL_TRAILERFUNC_OK;
1699+
}
1700+
1701+
lua_settop(L, top);
1702+
return CURL_TRAILERFUNC_ABORT;
1703+
}
1704+
1705+
static int lcurl_easy_set_TRAILERFUNCTION (lua_State *L){
1706+
lcurl_easy_t *p = lcurl_geteasy(L);
1707+
return lcurl_easy_set_callback(L, p, &p->trailer,
1708+
CURLOPT_TRAILERFUNCTION, CURLOPT_TRAILERDATA,
1709+
"trailer", lcurl_trailer_callback
1710+
);
1711+
}
1712+
1713+
#endif
1714+
1715+
//}
1716+
16211717
//}
16221718

16231719
static int lcurl_easy_setopt(lua_State *L){
@@ -1780,6 +1876,9 @@ static const struct luaL_Reg lcurl_easy_methods[] = {
17801876
#if LCURL_CURL_VER_GE(7,63,0)
17811877
OPT_ENTRY(curlu, CURLU, TTT, 0, 0)
17821878
#endif
1879+
#if LCURL_CURL_VER_GE(7,64,0)
1880+
OPT_ENTRY(trailerfunction, TRAILERFUNCTION, TTT, 0, 0)
1881+
#endif
17831882
#undef OPT_ENTRY
17841883

17851884
#define OPT_ENTRY(L, N, T, S, D) { "unsetopt_"#L, lcurl_easy_unset_##N },
@@ -1808,6 +1907,9 @@ static const struct luaL_Reg lcurl_easy_methods[] = {
18081907
#if LCURL_CURL_VER_GE(7,63,0)
18091908
OPT_ENTRY(curlu, CURLU, TTT, 0, 0)
18101909
#endif
1910+
#if LCURL_CURL_VER_GE(7,64,0)
1911+
OPT_ENTRY(trailerfunction, TRAILERFUNCTION, TTT, 0, 0)
1912+
#endif
18111913
#undef OPT_ENTRY
18121914

18131915
#define OPT_ENTRY(L, N, T, S) { "getinfo_"#L, lcurl_easy_get_##N },
@@ -1868,6 +1970,9 @@ static const lcurl_const_t lcurl_easy_opt[] = {
18681970
#if LCURL_CURL_VER_GE(7,63,0)
18691971
OPT_ENTRY(curlu, CURLU, TTT, 0, 0)
18701972
#endif
1973+
#if LCURL_CURL_VER_GE(7,64,0)
1974+
OPT_ENTRY(trailerfunction, TRAILERFUNCTION, TTT, 0, 0)
1975+
#endif
18711976
#undef OPT_ENTRY
18721977
#undef FLG_ENTRY
18731978

src/lceasy.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ typedef struct lcurl_easy_tag{
8989
lcurl_callback_t match;
9090
lcurl_callback_t chunk_bgn;
9191
lcurl_callback_t chunk_end;
92+
#if LCURL_CURL_VER_GE(7,64,0)
93+
lcurl_callback_t trailer;
94+
#endif
9295
}lcurl_easy_t;
9396

9497
int lcurl_easy_create(lua_State *L, int error_mode);

test/test_easy.lua

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ local json = require "dkjson"
1818
local path = require "path"
1919
local upath = require "path".new('/')
2020
local utils = require "utils"
21-
-- local url = "http://127.0.0.1:7090/get"
2221
local fname = "./test.download"
2322

2423
-- local GET_URL = "http://example.com"
@@ -1164,4 +1163,110 @@ end
11641163

11651164
end
11661165

1166+
local _ENV = TEST_CASE'trailer_callback' if ENABLE and is_curl_ge(7,64,0) then
1167+
1168+
local url = POST_URL
1169+
1170+
local m, c, t
1171+
1172+
local function json_data()
1173+
return json.decode(table.concat(t))
1174+
end
1175+
1176+
local treader = function(t)
1177+
local i = 0
1178+
return function()
1179+
i = i + 1
1180+
return t[i]
1181+
end
1182+
end
1183+
1184+
function setup()
1185+
t = {}
1186+
c = assert(scurl.easy{
1187+
url = url,
1188+
post = true,
1189+
httpheader = {"Transfer-Encoding: chunked"},
1190+
readfunction = treader {'a=1&', 'b=2&'},
1191+
timeout = 60,
1192+
})
1193+
assert_equal(c, c:setopt_writefunction(table.insert, t))
1194+
end
1195+
1196+
function teardown()
1197+
if c then c:close() end
1198+
if m then m:close() end
1199+
t, c, m = nil
1200+
end
1201+
1202+
local empty_responses = {
1203+
{'no_response', function() end},
1204+
{'nil_response', function() return nil end},
1205+
{'null_response', function() return curl.null end},
1206+
{'true_response', function() return true end},
1207+
{'empty_array', function() return {} end},
1208+
}
1209+
1210+
local abort_responses = {
1211+
{'false_response', function() return false end},
1212+
{'nil_with_error_response', function() return nil, 'error message' end},
1213+
{'numeric_response_0', function() return 0 end},
1214+
{'numeric_response_1', function() return 1 end},
1215+
}
1216+
1217+
for _, response in ipairs(empty_responses) do
1218+
_ENV[ 'test_' .. response[1] ] = function()
1219+
local trailer_called = 0
1220+
assert_equal(c, c:setopt_trailerfunction(function()
1221+
trailer_called = trailer_called + 1
1222+
return response[2]()
1223+
end))
1224+
1225+
assert_equal(c, c:perform())
1226+
1227+
assert_equal(1, trailer_called)
1228+
1229+
assert_equal(200, c:getinfo_response_code())
1230+
local data = assert_table(json_data())
1231+
1232+
assert_equal('1', data.form.a)
1233+
assert_equal('2', data.form.b)
1234+
end
1235+
end
1236+
1237+
for _, response in ipairs(abort_responses) do
1238+
_ENV[ 'test_' .. response[1] ] = function()
1239+
local trailer_called = 0
1240+
assert_equal(c, c:setopt_trailerfunction(function()
1241+
trailer_called = trailer_called + 1
1242+
return response[2]()
1243+
end))
1244+
1245+
local ok, err = assert_nil(c:perform())
1246+
assert_equal(1, trailer_called)
1247+
assert_equal(curl.error(curl.ERROR_EASY, curl.E_ABORTED_BY_CALLBACK), err)
1248+
end
1249+
end
1250+
1251+
function test_send_header()
1252+
local trailer_called = 0
1253+
assert_equal(c, c:setopt_trailerfunction(function()
1254+
trailer_called = trailer_called + 1
1255+
return {'x-trailer-header: value'}
1256+
end))
1257+
1258+
assert_equal(c, c:perform())
1259+
1260+
assert_equal(1, trailer_called)
1261+
1262+
assert_equal(200, c:getinfo_response_code())
1263+
local data = assert_table(json_data())
1264+
1265+
assert_equal('1', data.form.a)
1266+
assert_equal('2', data.form.b)
1267+
assert_equal('value', data.headers['x-trailer-header'])
1268+
end
1269+
1270+
end
1271+
11671272
RUN()

0 commit comments

Comments
 (0)