Skip to content

Commit 56b4d05

Browse files
committed
Fix. Set Lua in callback context in info_read function.
Fix. Support nested callbacks. Fix. Cleanup easy references when calls multi::close. Add. `__tostring` method for handles.
1 parent b2e9474 commit 56b4d05

File tree

8 files changed

+180
-53
lines changed

8 files changed

+180
-53
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ script:
4646
- lunit.sh run.lua
4747
- lua test_pause02.c.lua
4848
- lua test_multi_callback.lua
49+
- lua test_multi_nested_callback.lua.lua
4950
# - lunit.sh test_easy.lua
5051
# - lunit.sh test_safe.lua
5152
# - lunit.sh test_form.lua

appveyor.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ test_script:
5757
- lua run.lua
5858
- lua test_pause02.c.lua
5959
- lua test_multi_callback.lua
60+
- lua test_multi_nested_callback.lua
6061

6162
after_test:
6263
- cd %APPVEYOR_BUILD_FOLDER%

src/lceasy.c

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,31 @@ static const char *LCURL_EASY = LCURL_EASY_NAME;
2828
# define LCURL_E_UNKNOWN_OPTION CURLE_UNKNOWN_TELNET_OPTION
2929
#endif
3030

31+
/* Before call curl_XXX function which can call any callback
32+
* need set Curren Lua thread pointer in easy/multi contexts.
33+
* But it also possible that we already in callback call.
34+
* E.g. `curl_easy_pause` function may be called from write callback.
35+
* and it even may be called in different thread.
36+
* ```Lua
37+
* multi:add_handle(easy)
38+
* easy:setopt_writefunction(function(...)
39+
* coroutine.wrap(function() multi:add_handle(easy2) end)()
40+
* end)
41+
* ```
42+
* So we have to restore previews Lua state in callback contexts.
43+
*/
44+
void lcurl__easy_assign_lua(lua_State *L, lcurl_easy_t *p, lua_State *value, int assign_multi){
45+
if(p->multi && assign_multi){
46+
lcurl__multi_assign_lua(L, p->multi, value, 1);
47+
}
48+
else{
49+
p->L = value;
50+
if(p->post){
51+
p->post->L = value;
52+
}
53+
}
54+
}
55+
3156
//{
3257

3358
int lcurl_easy_create(lua_State *L, int error_mode){
@@ -72,24 +97,25 @@ lcurl_easy_t *lcurl_geteasy_at(lua_State *L, int i){
7297
return p;
7398
}
7499

100+
static int lcurl_easy_to_s(lua_State *L){
101+
lcurl_easy_t *p = (lcurl_easy_t *)lutil_checkudatap (L, 1, LCURL_EASY);
102+
lua_pushfstring(L, LCURL_PREFIX " Easy (%p)", (void*)p);
103+
return 1;
104+
}
105+
75106
static int lcurl_easy_cleanup(lua_State *L){
76107
lcurl_easy_t *p = lcurl_geteasy(L);
77108
int i;
78109

79110
if(p->curl){
80-
p->L = L;
81-
if(p->post){
82-
p->post->L = L;
83-
}
111+
lua_State *curL;
112+
84113
// In my tests when I cleanup some easy handle.
85114
// timerfunction called only for single multi handle.
86-
if(p->multi){
87-
p->multi->L = L;
88-
}
115+
curL = p->L; lcurl__easy_assign_lua(L, p, L, 1);
89116
curl_easy_cleanup(p->curl);
90-
if(p->multi){
91-
p->multi->L = NULL;
92-
}
117+
lcurl__easy_assign_lua(L, p, curL, 1);
118+
93119
p->curl = NULL;
94120
}
95121

@@ -127,18 +153,17 @@ static int lcurl_easy_cleanup(lua_State *L){
127153
static int lcurl_easy_perform(lua_State *L){
128154
lcurl_easy_t *p = lcurl_geteasy(L);
129155
CURLcode code;
156+
lua_State *curL;
130157
int top = 1;
131158
lua_settop(L, top);
132159

133160
assert(p->rbuffer.ref == LUA_NOREF);
134161

135162
// store reference to current coroutine to callbacks
136-
p->L = L;
137-
if(p->post){
138-
p->post->L = L;
139-
}
140-
163+
// User should not call `perform` if handle assign to multi
164+
curL = p->L; lcurl__easy_assign_lua(L, p, L, 0);
141165
code = curl_easy_perform(p->curl);
166+
lcurl__easy_assign_lua(L, p, curL, 0);
142167

143168
if(p->rbuffer.ref != LUA_NOREF){
144169
luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref);
@@ -744,6 +769,7 @@ static size_t lcurl_write_callback_(lua_State*L,
744769

745770
static size_t lcurl_write_callback(char *ptr, size_t size, size_t nmemb, void *arg){
746771
lcurl_easy_t *p = arg;
772+
assert(NULL != p->L);
747773
return lcurl_write_callback_(p->L, p, &p->wr, ptr, size, nmemb);
748774
}
749775

@@ -847,11 +873,13 @@ static size_t lcurl_easy_read_callback(char *buffer, size_t size, size_t nitems,
847873
if(p->magic == LCURL_HPOST_STREAM_MAGIC){
848874
return lcurl_hpost_read_callback(buffer, size, nitems, arg);
849875
}
876+
assert(NULL != p->L);
850877
return lcurl_read_callback(p->L, &p->rd, &p->rbuffer, buffer, size, nitems);
851878
}
852879

853880
static size_t lcurl_hpost_read_callback(char *buffer, size_t size, size_t nitems, void *arg){
854881
lcurl_hpost_stream_t *p = arg;
882+
assert(NULL != p->L);
855883
return lcurl_read_callback(*p->L, &p->rd, &p->rbuffer, buffer, size, nitems);
856884
}
857885

@@ -869,6 +897,7 @@ static int lcurl_easy_set_READFUNCTION(lua_State *L){
869897

870898
static size_t lcurl_header_callback(char *ptr, size_t size, size_t nmemb, void *arg){
871899
lcurl_easy_t *p = arg;
900+
assert(NULL != p->L);
872901
return lcurl_write_callback_(p->L, p, &p->hd, ptr, size, nmemb);
873902
}
874903

@@ -889,10 +918,12 @@ static int lcurl_xferinfo_callback(void *arg, curl_off_t dltotal, curl_off_t dln
889918
{
890919
lcurl_easy_t *p = arg;
891920
lua_State *L = p->L;
921+
int n, top, ret = 0;
922+
923+
assert(NULL != p->L);
892924

893-
int ret = 0;
894-
int top = lua_gettop(L);
895-
int n = lcurl_util_push_cb(L, &p->pr);
925+
top = lua_gettop(L);
926+
n = lcurl_util_push_cb(L, &p->pr);
896927

897928
lua_pushnumber( L, (lua_Number)dltotal );
898929
lua_pushnumber( L, (lua_Number)dlnow );
@@ -1033,8 +1064,14 @@ static int lcurl_easy_getinfo(lua_State *L){
10331064

10341065
static int lcurl_easy_pause(lua_State *L){
10351066
lcurl_easy_t *p = lcurl_geteasy(L);
1067+
lua_State *curL;
10361068
int mask = luaL_checkint(L, 2);
1037-
CURLcode code = curl_easy_pause(p->curl, mask);
1069+
CURLcode code;
1070+
1071+
curL = p->L; lcurl__easy_assign_lua(L, p, L, 1);
1072+
code = curl_easy_pause(p->curl, mask);
1073+
lcurl__easy_assign_lua(L, p, curL, 1);
1074+
10381075
if(code != CURLE_OK){
10391076
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
10401077
}
@@ -1096,19 +1133,20 @@ static const struct luaL_Reg lcurl_easy_methods[] = {
10961133
#include "lcinfoeasy.h"
10971134
#undef OPT_ENTRY
10981135

1099-
{ "pause", lcurl_easy_pause },
1100-
{ "reset", lcurl_easy_reset },
1101-
{ "setopt", lcurl_easy_setopt },
1102-
{ "getinfo", lcurl_easy_getinfo },
1103-
{ "unsetopt", lcurl_easy_unsetopt },
1104-
{ "escape", lcurl_easy_escape },
1105-
{ "unescape", lcurl_easy_unescape },
1106-
{ "perform", lcurl_easy_perform },
1107-
{ "close", lcurl_easy_cleanup },
1108-
{ "__gc", lcurl_easy_cleanup },
1109-
1110-
{ "setdata", lcurl_easy_setdata },
1111-
{ "getdata", lcurl_easy_getdata },
1136+
{ "pause", lcurl_easy_pause },
1137+
{ "reset", lcurl_easy_reset },
1138+
{ "setopt", lcurl_easy_setopt },
1139+
{ "getinfo", lcurl_easy_getinfo },
1140+
{ "unsetopt", lcurl_easy_unsetopt },
1141+
{ "escape", lcurl_easy_escape },
1142+
{ "unescape", lcurl_easy_unescape },
1143+
{ "perform", lcurl_easy_perform },
1144+
{ "close", lcurl_easy_cleanup },
1145+
{ "__gc", lcurl_easy_cleanup },
1146+
{ "__tostring", lcurl_easy_to_s },
1147+
1148+
{ "setdata", lcurl_easy_setdata },
1149+
{ "getdata", lcurl_easy_getdata },
11121150

11131151
{NULL,NULL}
11141152
};

src/lceasy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,6 @@ lcurl_easy_t *lcurl_geteasy_at(lua_State *L, int i);
6565

6666
void lcurl_easy_initlib(lua_State *L, int nup);
6767

68+
void lcurl__easy_assign_lua(lua_State *L, lcurl_easy_t *p, lua_State *value, int assign_multi);
69+
6870
#endif

src/lcmulti.c

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,19 @@
2828
#define LCURL_MULTI_NAME LCURL_PREFIX" Multi"
2929
static const char *LCURL_MULTI = LCURL_MULTI_NAME;
3030

31-
static void lcurl__multi_assign_lua(lua_State *L, lcurl_multi_t *p, int assign_easy){
32-
p->L = L;
33-
34-
if(assign_easy){
31+
void lcurl__multi_assign_lua(lua_State *L, lcurl_multi_t *p, lua_State *value, int assign_easy){
32+
if((assign_easy)&&(p->L != value)){
3533
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref);
3634
lua_pushnil(L);
3735
while(lua_next(L, -2)){
3836
lcurl_easy_t *e = lcurl_geteasy_at(L, -1);
39-
e->L = L;
40-
if(e->post){
41-
e->post->L = L;
42-
}
37+
lcurl__easy_assign_lua(L, e, value, 0);
4338
lua_pop(L, 1);
4439
}
4540
lua_pop(L, 1);
4641
}
42+
43+
p->L = value;
4744
}
4845

4946
//{
@@ -78,6 +75,12 @@ lcurl_multi_t *lcurl_getmulti_at(lua_State *L, int i){
7875
return p;
7976
}
8077

78+
static int lcurl_multi_to_s(lua_State *L){
79+
lcurl_multi_t *p = (lcurl_multi_t *)lutil_checkudatap (L, 1, LCURL_MULTI);
80+
lua_pushfstring(L, LCURL_PREFIX " Multi (%p)", (void*)p);
81+
return 1;
82+
}
83+
8184
static int lcurl_multi_cleanup(lua_State *L){
8285
lcurl_multi_t *p = lcurl_getmulti(L);
8386
if(p->curl){
@@ -86,6 +89,14 @@ static int lcurl_multi_cleanup(lua_State *L){
8689
}
8790

8891
if(p->h_ref != LUA_NOREF){
92+
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref);
93+
lua_pushnil(L);
94+
while(lua_next(L, -2)){
95+
lcurl_easy_t *e = lcurl_geteasy_at(L, -1);
96+
e->multi = NULL;
97+
lua_pop(L, 1);
98+
}
99+
lua_pop(L, 1);
89100
luaL_unref(L, LCURL_LUA_REGISTRY, p->h_ref);
90101
p->h_ref = LUA_NOREF;
91102
}
@@ -108,6 +119,7 @@ static int lcurl_multi_add_handle(lua_State *L){
108119
lcurl_multi_t *p = lcurl_getmulti(L);
109120
lcurl_easy_t *e = lcurl_geteasy_at(L, 2);
110121
CURLMcode code;
122+
lua_State *curL;
111123

112124
if(e->multi){
113125
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI,
@@ -135,9 +147,9 @@ static int lcurl_multi_add_handle(lua_State *L){
135147

136148
e->multi = p;
137149

138-
lcurl__multi_assign_lua(L, p, 0);
150+
curL = p->L; lcurl__multi_assign_lua(L, p, L, 1);
139151
code = curl_multi_add_handle(p->curl, e->curl);
140-
p->L = NULL;
152+
lcurl__multi_assign_lua(L, p, curL, 1);
141153

142154
if(code != CURLM_OK){
143155
// remove
@@ -155,6 +167,7 @@ static int lcurl_multi_remove_handle(lua_State *L){
155167
lcurl_multi_t *p = lcurl_getmulti(L);
156168
lcurl_easy_t *e = lcurl_geteasy_at(L, 2);
157169
CURLMcode code;
170+
lua_State *curL;
158171

159172
if(e->multi != p){
160173
// cURL returns CURLM_OK for such call so we do the same.
@@ -163,9 +176,9 @@ static int lcurl_multi_remove_handle(lua_State *L){
163176
return 1;
164177
}
165178

166-
lcurl__multi_assign_lua(L, p, 0);
179+
curL = p->L; lcurl__multi_assign_lua(L, p, L, 1);
167180
code = curl_multi_remove_handle(p->curl, e->curl);
168-
p->L = NULL;
181+
lcurl__multi_assign_lua(L, p, curL, 1);
169182

170183
if(code != CURLM_OK){
171184
lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, code);
@@ -183,10 +196,11 @@ static int lcurl_multi_perform(lua_State *L){
183196
lcurl_multi_t *p = lcurl_getmulti(L);
184197
int running_handles = 0;
185198
CURLMcode code;
199+
lua_State *curL;
186200

187-
lcurl__multi_assign_lua(L, p, 1);
201+
curL = p->L; lcurl__multi_assign_lua(L, p, L, 1);
188202
while((code = curl_multi_perform(p->curl, &running_handles)) == CURLM_CALL_MULTI_PERFORM);
189-
p->L = NULL;
203+
lcurl__multi_assign_lua(L, p, curL, 1);
190204

191205
if(code != CURLM_OK){
192206
lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, code);
@@ -213,7 +227,14 @@ static int lcurl_multi_info_read(lua_State *L){
213227
e = lcurl_geteasy_at(L, -1);
214228
if(remove){
215229
//! @fixme We ignore any errors
216-
if(CURLM_OK == curl_multi_remove_handle(p->curl, e->curl)){
230+
CURLMcode code;
231+
lua_State *curL;
232+
233+
curL = p->L; lcurl__multi_assign_lua(L, p, L, 1);
234+
code = curl_multi_remove_handle(p->curl, e->curl);
235+
lcurl__multi_assign_lua(L, p, curL, 1);
236+
237+
if(CURLM_OK == code){
217238
e->multi = NULL;
218239
lua_pushnil(L);
219240
lua_rawsetp(L, -3, e->curl);
@@ -309,12 +330,14 @@ static int lcurl_multi_socket_action(lua_State *L){
309330
lcurl_multi_t *p = lcurl_getmulti(L);
310331
curl_socket_t s = lutil_optint64(L, 2, CURL_SOCKET_TIMEOUT);
311332
CURLMcode code; int n, mask;
333+
lua_State *curL;
334+
312335
if(s == CURL_SOCKET_TIMEOUT) mask = lutil_optint64(L, 3, 0);
313336
else mask = lutil_checkint64(L, 3);
314337

315-
lcurl__multi_assign_lua(L, p, 1);
338+
curL = p->L; lcurl__multi_assign_lua(L, p, L, 1);
316339
code = curl_multi_socket_action(p->curl, s, mask, &n);
317-
p->L = NULL;
340+
lcurl__multi_assign_lua(L, p, curL, 1);
318341

319342
if(code != CURLM_OK){
320343
lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, code);
@@ -415,10 +438,12 @@ static int lcurl_multi_set_callback(lua_State *L,
415438
int lcurl_multi_timer_callback(CURLM *multi, long ms, void *arg){
416439
lcurl_multi_t *p = arg;
417440
lua_State *L = p->L;
441+
int n, top, ret = 0;
418442

419-
int ret = 0;
420-
int top = lua_gettop(L);
421-
int n = lcurl_util_push_cb(L, &p->tm);
443+
assert(NULL != p->L);
444+
445+
top = lua_gettop(L);
446+
n = lcurl_util_push_cb(L, &p->tm);
422447

423448
lua_pushnumber(L, ms);
424449
if(lua_pcall(L, n, LUA_MULTRET, 0)){
@@ -460,8 +485,11 @@ static int lcurl_multi_socket_callback(CURL *easy, curl_socket_t s, int what, vo
460485
lcurl_multi_t *p = arg;
461486
lua_State *L = p->L;
462487
lcurl_easy_t *e;
463-
int n, top = lua_gettop(L);
488+
int n, top;
489+
490+
assert(NULL != p->L);
464491

492+
top = lua_gettop(L);
465493
n = lcurl_util_push_cb(L, &p->sc);
466494

467495
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref);
@@ -547,6 +575,7 @@ static const struct luaL_Reg lcurl_multi_methods[] = {
547575
{"wait", lcurl_multi_wait },
548576
{"timeout", lcurl_multi_timeout },
549577
{"socket_action", lcurl_multi_socket_action },
578+
{ "__tostring", lcurl_multi_to_s },
550579

551580
#define OPT_ENTRY(L, N, T, S) { "setopt_"#L, lcurl_multi_set_##N },
552581
#include "lcoptmulti.h"

src/lcmulti.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@ lcurl_multi_t *lcurl_getmulti_at(lua_State *L, int i);
3131

3232
void lcurl_multi_initlib(lua_State *L, int nup);
3333

34+
void lcurl__multi_assign_lua(lua_State *L, lcurl_multi_t *p, lua_State *value, int assign_easy);
35+
3436
#endif

0 commit comments

Comments
 (0)