1414#include "lcutils.h"
1515#include "lchttppost.h"
1616#include "lcshare.h"
17+ #include "lcmulti.h"
1718#include <memory.h>
1819
1920static 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
3260int 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
6796lcurl_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+
73108static 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){
113164static 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
731784static 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
839894static 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
856912static 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
10201079static 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};
0 commit comments