Skip to content

Commit 2798a61

Browse files
authored
Merge pull request #80 from moteus/master
Fix. Call `multi` callbacks with correct Lua state Fix. Support nested callbacks. Fix. `easy:close` removes self from `multi` handle. Add. `__tostring` metamethod
2 parents 90c1777 + c5e4734 commit 2798a61

File tree

13 files changed

+496
-57
lines changed

13 files changed

+496
-57
lines changed

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ script:
4545
- lua -e "print(require 'cURL.utils'.find_ca_bundle())"
4646
- lunit.sh run.lua
4747
- lua test_pause02.c.lua
48+
- lua test_multi_callback.lua
49+
- lua test_multi_nested_callback.lua
4850
# - lunit.sh test_easy.lua
4951
# - lunit.sh test_safe.lua
5052
# - lunit.sh test_form.lua

appveyor.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ test_script:
5656
- cd %APPVEYOR_BUILD_FOLDER%\test
5757
- lua run.lua
5858
- lua test_pause02.c.lua
59+
- lua test_multi_callback.lua
60+
- lua test_multi_nested_callback.lua
5961

6062
after_test:
6163
- cd %APPVEYOR_BUILD_FOLDER%

examples/cURLv3/uvwget.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ end
182182

183183
on_curl_action = function(easy, fd, action)
184184
local ok, err = pcall(function()
185-
trace("CURL::SOCKET", easy, s, ACTION_NAMES[action] or action)
185+
trace("CURL::SOCKET", easy, fd, ACTION_NAMES[action] or action)
186186

187187
local context = easy.data.context
188188

lakefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ PROJECT = 'cURL'
22

33
INITLAKEFILE()
44

5-
DEFINES = L{DEFINES,
5+
DEFINES = L{DEFINES,
66
IF(WINDOWS, 'DLL_EXPORT', '');
7+
IF(DEBUG, 'LCURL_RESET_NULL_LUA', '');
78
}
89

910
cURL = c.shared{'lcurl',
@@ -18,7 +19,7 @@ cURL = c.shared{'lcurl',
1819
target('build', cURL)
1920

2021
install = target('install', {
21-
file.group{odir=LIBDIR; src = cURL };
22+
file.group{odir=LIBDIR; src = cURL };
2223
file.group{odir=LIBDIR; src = J("src", "lua") ; recurse = true };
2324
file.group{odir=J(ROOT, 'examples'); src = 'examples'; recurse = true };
2425
file.group{odir=TESTDIR; src = 'test'; recurse = true };
@@ -30,6 +31,8 @@ target('test', install, function()
3031
run_test('test_form.lua')
3132
run_test('test_pause02.c.lua')
3233
run_test('test_curl.lua')
34+
run_test('test_multi_callback.lua')
35+
run_test('test_multi_nested_callback.lua')
3336

3437
if not test_summary() then
3538
quit("test fail")

src/lceasy.c

Lines changed: 92 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "lcutils.h"
1515
#include "lchttppost.h"
1616
#include "lcshare.h"
17+
#include "lcmulti.h"
1718
#include <memory.h>
1819

1920
static const char *LCURL_ERROR_TAG = "LCURL_ERROR_TAG";
@@ -27,6 +28,33 @@ static const char *LCURL_EASY = LCURL_EASY_NAME;
2728
# define LCURL_E_UNKNOWN_OPTION CURLE_UNKNOWN_TELNET_OPTION
2829
#endif
2930

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+
* But if previews Lua state is NULL then we can just do not set it back.
44+
* But set it to NULL make esier debug code.
45+
*/
46+
void lcurl__easy_assign_lua(lua_State *L, lcurl_easy_t *p, lua_State *value, int assign_multi){
47+
if(p->multi && assign_multi){
48+
lcurl__multi_assign_lua(L, p->multi, value, 1);
49+
}
50+
else{
51+
p->L = value;
52+
if(p->post){
53+
p->post->L = value;
54+
}
55+
}
56+
}
57+
3058
//{
3159

3260
int lcurl_easy_create(lua_State *L, int error_mode){
@@ -45,6 +73,7 @@ int lcurl_easy_create(lua_State *L, int error_mode){
4573
p->magic = LCURL_EASY_MAGIC;
4674
p->L = NULL;
4775
p->post = NULL;
76+
p->multi = NULL;
4877
p->storage = lcurl_storage_init(L);
4978
p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF;
5079
p->rd.cb_ref = p->rd.ud_ref = LUA_NOREF;
@@ -66,16 +95,38 @@ int lcurl_easy_create(lua_State *L, int error_mode){
6695

6796
lcurl_easy_t *lcurl_geteasy_at(lua_State *L, int i){
6897
lcurl_easy_t *p = (lcurl_easy_t *)lutil_checkudatap (L, i, LCURL_EASY);
69-
luaL_argcheck (L, p != NULL, 1, LCURL_EASY_NAME" expected");
98+
luaL_argcheck (L, p != NULL, 1, LCURL_EASY_NAME" object expected");
7099
return p;
71100
}
72101

102+
static int lcurl_easy_to_s(lua_State *L){
103+
lcurl_easy_t *p = (lcurl_easy_t *)lutil_checkudatap (L, 1, LCURL_EASY);
104+
lua_pushfstring(L, LCURL_EASY_NAME" (%p)", (void*)p);
105+
return 1;
106+
}
107+
73108
static int lcurl_easy_cleanup(lua_State *L){
74109
lcurl_easy_t *p = lcurl_geteasy(L);
75110
int i;
76111

112+
if(p->multi){
113+
CURLMcode code = lcurl__multi_remove_handle(L, p->multi, p);
114+
115+
//! @todo what I can do if I can not remove it???
116+
}
117+
77118
if(p->curl){
119+
lua_State *curL;
120+
121+
// In my tests when I cleanup some easy handle.
122+
// timerfunction called only for single multi handle.
123+
curL = p->L; lcurl__easy_assign_lua(L, p, L, 1);
78124
curl_easy_cleanup(p->curl);
125+
#ifndef LCURL_RESET_NULL_LUA
126+
if(curL != NULL)
127+
#endif
128+
lcurl__easy_assign_lua(L, p, curL, 1);
129+
79130
p->curl = NULL;
80131
}
81132

@@ -113,18 +164,20 @@ static int lcurl_easy_cleanup(lua_State *L){
113164
static int lcurl_easy_perform(lua_State *L){
114165
lcurl_easy_t *p = lcurl_geteasy(L);
115166
CURLcode code;
167+
lua_State *curL;
116168
int top = 1;
117169
lua_settop(L, top);
118170

119171
assert(p->rbuffer.ref == LUA_NOREF);
120172

121173
// store reference to current coroutine to callbacks
122-
p->L = L;
123-
if(p->post){
124-
p->post->L = L;
125-
}
126-
174+
// User should not call `perform` if handle assign to multi
175+
curL = p->L; lcurl__easy_assign_lua(L, p, L, 0);
127176
code = curl_easy_perform(p->curl);
177+
#ifndef LCURL_RESET_NULL_LUA
178+
if(curL != NULL)
179+
#endif
180+
lcurl__easy_assign_lua(L, p, curL, 0);
128181

129182
if(p->rbuffer.ref != LUA_NOREF){
130183
luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref);
@@ -730,6 +783,7 @@ static size_t lcurl_write_callback_(lua_State*L,
730783

731784
static size_t lcurl_write_callback(char *ptr, size_t size, size_t nmemb, void *arg){
732785
lcurl_easy_t *p = arg;
786+
assert(NULL != p->L);
733787
return lcurl_write_callback_(p->L, p, &p->wr, ptr, size, nmemb);
734788
}
735789

@@ -833,11 +887,13 @@ static size_t lcurl_easy_read_callback(char *buffer, size_t size, size_t nitems,
833887
if(p->magic == LCURL_HPOST_STREAM_MAGIC){
834888
return lcurl_hpost_read_callback(buffer, size, nitems, arg);
835889
}
890+
assert(NULL != p->L);
836891
return lcurl_read_callback(p->L, &p->rd, &p->rbuffer, buffer, size, nitems);
837892
}
838893

839894
static size_t lcurl_hpost_read_callback(char *buffer, size_t size, size_t nitems, void *arg){
840895
lcurl_hpost_stream_t *p = arg;
896+
assert(NULL != p->L);
841897
return lcurl_read_callback(*p->L, &p->rd, &p->rbuffer, buffer, size, nitems);
842898
}
843899

@@ -855,6 +911,7 @@ static int lcurl_easy_set_READFUNCTION(lua_State *L){
855911

856912
static size_t lcurl_header_callback(char *ptr, size_t size, size_t nmemb, void *arg){
857913
lcurl_easy_t *p = arg;
914+
assert(NULL != p->L);
858915
return lcurl_write_callback_(p->L, p, &p->hd, ptr, size, nmemb);
859916
}
860917

@@ -875,10 +932,12 @@ static int lcurl_xferinfo_callback(void *arg, curl_off_t dltotal, curl_off_t dln
875932
{
876933
lcurl_easy_t *p = arg;
877934
lua_State *L = p->L;
935+
int n, top, ret = 0;
878936

879-
int ret = 0;
880-
int top = lua_gettop(L);
881-
int n = lcurl_util_push_cb(L, &p->pr);
937+
assert(NULL != p->L);
938+
939+
top = lua_gettop(L);
940+
n = lcurl_util_push_cb(L, &p->pr);
882941

883942
lua_pushnumber( L, (lua_Number)dltotal );
884943
lua_pushnumber( L, (lua_Number)dlnow );
@@ -1019,8 +1078,17 @@ static int lcurl_easy_getinfo(lua_State *L){
10191078

10201079
static int lcurl_easy_pause(lua_State *L){
10211080
lcurl_easy_t *p = lcurl_geteasy(L);
1081+
lua_State *curL;
10221082
int mask = luaL_checkint(L, 2);
1023-
CURLcode code = curl_easy_pause(p->curl, mask);
1083+
CURLcode code;
1084+
1085+
curL = p->L; lcurl__easy_assign_lua(L, p, L, 1);
1086+
code = curl_easy_pause(p->curl, mask);
1087+
#ifndef LCURL_RESET_NULL_LUA
1088+
if(curL != NULL)
1089+
#endif
1090+
lcurl__easy_assign_lua(L, p, curL, 1);
1091+
10241092
if(code != CURLE_OK){
10251093
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
10261094
}
@@ -1080,19 +1148,20 @@ static const struct luaL_Reg lcurl_easy_methods[] = {
10801148
#include "lcinfoeasy.h"
10811149
#undef OPT_ENTRY
10821150

1083-
{ "pause", lcurl_easy_pause },
1084-
{ "reset", lcurl_easy_reset },
1085-
{ "setopt", lcurl_easy_setopt },
1086-
{ "getinfo", lcurl_easy_getinfo },
1087-
{ "unsetopt", lcurl_easy_unsetopt },
1088-
{ "escape", lcurl_easy_escape },
1089-
{ "unescape", lcurl_easy_unescape },
1090-
{ "perform", lcurl_easy_perform },
1091-
{ "close", lcurl_easy_cleanup },
1092-
{ "__gc", lcurl_easy_cleanup },
1093-
1094-
{ "setdata", lcurl_easy_setdata },
1095-
{ "getdata", lcurl_easy_getdata },
1151+
{ "pause", lcurl_easy_pause },
1152+
{ "reset", lcurl_easy_reset },
1153+
{ "setopt", lcurl_easy_setopt },
1154+
{ "getinfo", lcurl_easy_getinfo },
1155+
{ "unsetopt", lcurl_easy_unsetopt },
1156+
{ "escape", lcurl_easy_escape },
1157+
{ "unescape", lcurl_easy_unescape },
1158+
{ "perform", lcurl_easy_perform },
1159+
{ "close", lcurl_easy_cleanup },
1160+
{ "__gc", lcurl_easy_cleanup },
1161+
{ "__tostring", lcurl_easy_to_s },
1162+
1163+
{ "setdata", lcurl_easy_setdata },
1164+
{ "getdata", lcurl_easy_getdata },
10961165

10971166
{NULL,NULL}
10981167
};

src/lceasy.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ enum {
3535

3636
#define LCURL_EASY_MAGIC 0xEA
3737

38+
typedef struct lcurl_multi_tag lcurl_multi_t;
39+
3840
typedef struct lcurl_easy_tag{
3941
unsigned char magic;
4042

@@ -44,6 +46,8 @@ typedef struct lcurl_easy_tag{
4446

4547
lcurl_hpost_t *post;
4648

49+
lcurl_multi_t *multi;
50+
4751
CURL *curl;
4852
int storage;
4953
int lists[LCURL_LIST_COUNT];
@@ -61,4 +65,6 @@ lcurl_easy_t *lcurl_geteasy_at(lua_State *L, int i);
6165

6266
void lcurl_easy_initlib(lua_State *L, int nup);
6367

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

src/lchttppost.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,16 @@ int lcurl_hpost_create(lua_State *L, int error_mode){
112112

113113
lcurl_hpost_t *lcurl_gethpost_at(lua_State *L, int i){
114114
lcurl_hpost_t *p = (lcurl_hpost_t *)lutil_checkudatap (L, i, LCURL_HTTPPOST);
115-
luaL_argcheck (L, p != NULL, 1, LCURL_PREFIX"HTTPPost object expected");
115+
luaL_argcheck (L, p != NULL, 1, LCURL_HTTPPOST_NAME" object expected");
116116
return p;
117117
}
118118

119+
static int lcurl_hpost_to_s(lua_State *L){
120+
lcurl_hpost_t *p = (lcurl_hpost_t *)lutil_checkudatap (L, 1, LCURL_HTTPPOST);
121+
lua_pushfstring(L, LCURL_HTTPPOST_NAME" (%p)", (void*)p);
122+
return 1;
123+
}
124+
119125
static int lcurl_hpost_add_content(lua_State *L){
120126
// add_buffer(name, data, [type,] [headers])
121127
lcurl_hpost_t *p = lcurl_gethpost(L);

0 commit comments

Comments
 (0)