/****************************************************************************** cURL_Lua, Lua bindings for cURL ****************************************************************************** Released under the GNU/GPL license or MIT license (at your option), no warranties. Author: - Enrico Tassi status: - binds from 7.9.5 to 7.11.2 changelog: - first public release todo: - WRITE_CB,READ_CB,DEBUG_CB must be identifyed by a unique pointer, but using CURL* + OFFSET may not be the case... think a bit more - CURLINFO ??? ****************************************************************************** $Id: curl_lua.c,v 1.26 2006/01/13 21:46:54 gareuselesinge Exp $ ******************************************************************************/ #include #include #include #include #include #include #include #include "luabind.h" #include "compat-5.1.h" #define CURL_EASY_META_NAME "curleasy.type" /* think more if this means unicity... maybe store in the bag some pointers */ /* this need that a has size > bigger_offset */ #define CURL_WRITECB_OFF(a) ((void*)(((char*)a)+0)) #define CURL_READCB_OFF(a) ((void*)(((char*)a)+1)) #define CURL_HEADCB_OFF(a) ((void*)(((char*)a)+2)) /* to check the curl version on the fly, this is a v >= LIBCURL_VERSION */ #define CURL_NEWER(M,m,p) ((p + (m << 8) + (M << 16)) <= LIBCURL_VERSION_NUM) #define CURL_OLDER(M,m,p) ((p + (m << 8) + (M << 16)) > LIBCURL_VERSION_NUM) /* some compatibility for name aliases */ #ifndef CURLOPT_WRITEDATA #define CURLOPT_WRITEDATA CURLOPT_FILE #endif #ifndef CURLOPT_READDATA #define CURLOPT_READDATA CURLOPT_INFILE #endif #ifndef CURLOPT_HEADERDATA #define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER #endif /* strings put in the bag, vectorialized for faster/shorter access */ #define STR_CAINFO 0 #define STR_COOKIE 1 #define STR_COOKIEFILE 2 #define STR_COOKIEJAR 3 #define STR_CUSTOMREQUEST 4 #define STR_EGDSOCKET 5 #define STR_FTPPORT 6 #define STR_INTERFACE 7 #define STR_KRB4LEVEL 8 #define STR_POSTFIELDS 9 #define STR_PROXY 10 #define STR_PROXYUSERPWD 11 #define STR_RANDOM_FILE 12 #define STR_RANGE 13 #define STR_REFERER 14 #define STR_SSLCERT 15 #define STR_SSLCERTPASSWD 16 #define STR_SSLCERTTYPE 17 #define STR_SSLENGINE 18 #define STR_SSLKEY 19 #define STR_SSLKEYTYPE 20 #define STR_SSL_CIPHER_LIST 21 #define STR_URL 22 #define STR_USERAGENT 23 #define STR_USERPWD 24 #define STR_LAST STR_USERPWD #if CURL_NEWER(7,9,8) #define STR_CAPATH 25 #undef STR_LAST #define STR_LAST STR_CAPATH #endif #if CURL_NEWER(7,10,0) #define STR_ENCODING 26 #undef STR_LAST #define STR_LAST STR_ENCODING #endif #if CURL_NEWER(7,10,3) #define STR_PRIVATE 27 #undef STR_LAST #define STR_LAST STR_PRIVATE #endif #if CURL_NEWER(7,11,0) #define STR_NETRC_FILE 28 #undef STR_LAST #define STR_LAST STR_NETRC_FILE #endif #define STR_SIZE (STR_LAST + 1) /****************************************************************************** * we need to keep with us the CURL handler plus some buffers * */ struct L_curl_bag { CURL* handler; char* strings[STR_SIZE]; char err[CURL_ERROR_SIZE]; struct curl_slist * headlist; #if CURL_NEWER(7,9,6) struct curl_httppost *post; #endif }; /****************************************************************************** * table created with this script: * * cat /usr/include/curl/curl.h | grep "^ *CINIT(" | \ * sed "s/CINIT(/{\"OPT_/" | sed -r "s/, +/\",CURLOPTTYPE_/" | \ * sed "s/, / + /" | sed "s/),/},/" > curlopt.h * */ static const struct L_const curl_easy_c [] = { #include "curlopt.h" {NULL,0} }; /****************************************************************************** * table created with this script: * * cat /usr/include/curl/curl.h | grep "^ *CURL_NETRC_[A-Z]*," | \ * cut -f 1 -d "," | \ * awk '{print "{\"" $1 "\", (int)" $1 "}," }' | \ * sed "s/CURL_//" > curl_netrcopt.h */ #if CURL_NEWER(7,9,8) static const struct L_const curl_easy_netrc_c [] = { #include "curl_netrcopt.h" {NULL,0} }; #endif /****************************************************************************** * table created with this script: * * cat /usr/include/curl/curl.h | grep "CURLAUTH_" | \ * sed "s/#define *CURL/{\"/" | sed "s/ *\/\*.*\*\///" | \ * sed "s/ /\",/" | sed "s/$$/},/" > curl_authopt.h */ #if CURL_NEWER(7,10,6) static const struct L_const curl_easy_auth_c [] = { #include "curl_authopt.h" {NULL,0} }; #endif /****************************************************************************** * table created by hand: * */ static const struct L_const curl_easy_httpver_c [] = { {"HTTP_VERSION_NONE",CURL_HTTP_VERSION_NONE}, {"HTTP_VERSION_1_0",CURL_HTTP_VERSION_1_0}, {"HTTP_VERSION_1_1",CURL_HTTP_VERSION_1_1}, {NULL,0} }; /****************************************************************************** * table created by hand: * */ #if CURL_NEWER(7,11,0) static const struct L_const curl_easy_ftpssl_c [] = { {"FTPSSL_NONE",CURLFTPSSL_NONE}, {"FTPSSL_TRY",CURLFTPSSL_TRY}, {"FTPSSL_CONTROL",CURLFTPSSL_CONTROL}, {"FTPSSL_ALL",CURLFTPSSL_ALL}, {NULL,0} }; #endif /****************************************************************************** * table created by hand: * */ static const struct L_const curl_easy_closepolicy_c [] = { {"CLOSEPOLICY_LEAST_RECENTLY_USED",CURLCLOSEPOLICY_LEAST_RECENTLY_USED}, {"CLOSEPOLICY_OLDEST",CURLCLOSEPOLICY_OLDEST}, {NULL,0} }; /****************************************************************************** * table created by hand: * */ #if CURL_NEWER(7,10,8) static const struct L_const curl_easy_ipresolve_c [] = { {"IPRESOLVE_WHATEVER",CURL_IPRESOLVE_WHATEVER}, {"IPRESOLVE_V4",CURL_IPRESOLVE_V4}, {"IPRESOLVE_V6",CURL_IPRESOLVE_V6}, {NULL,0} }; #endif /****************************************************************************** * table created by hand: * */ #if CURL_NEWER(7,10,0) static const struct L_const curl_easy_proxytype_c [] = { {"PROXY_HTTP",CURLPROXY_HTTP}, {"PROXY_SOCKS5",CURLPROXY_SOCKS5}, {NULL,0} }; #endif /****************************************************************************** * table created with this script: * * cat /usr/include/curl/curl.h | grep "^ *CFINIT" | \ * grep -v "CFINIT(NOTHING)" | sed "s/CFINIT(//" | \ * sed "s/),/ ,/" | \ * awk '{print "{\"FORM_" $1 "\",CURLFORM_" $1 "}," }' > \ * curl_form.h */ static const struct L_const curl_easy_form_c [] = { #include "curl_form.h" {NULL,0} }; /****************************************************************************** * checks and returns a CURL* handler from the first position in the stack * */ static CURL* L_checkcurleasy(lua_State*L) { void* tmp = luaL_checkudata(L,1,CURL_EASY_META_NAME); luaL_argcheck(L,tmp != NULL,1,"curleasy expected"); return ((struct L_curl_bag*)tmp)->handler; } /****************************************************************************** * checks and returns the userdata * */ static struct L_curl_bag* L_checkcurluserdata(lua_State*L) { void* tmp = luaL_checkudata(L,1,CURL_EASY_META_NAME); luaL_argcheck(L,tmp != NULL,1,"curleasy expected"); return ((struct L_curl_bag*)tmp); } /****************************************************************************** * maps a curl option to the right bag.strings[] element * */ static unsigned int L_CURLoption2vect(lua_State*L,CURLoption opt){ switch (opt) { case CURLOPT_CAINFO: return STR_CAINFO; case CURLOPT_COOKIE: return STR_COOKIE; case CURLOPT_COOKIEFILE: return STR_COOKIEFILE; case CURLOPT_COOKIEJAR: return STR_COOKIEJAR; case CURLOPT_CUSTOMREQUEST: return STR_CUSTOMREQUEST; case CURLOPT_EGDSOCKET: return STR_EGDSOCKET; case CURLOPT_FTPPORT: return STR_FTPPORT; case CURLOPT_INTERFACE: return STR_INTERFACE; case CURLOPT_KRB4LEVEL: return STR_KRB4LEVEL; case CURLOPT_POSTFIELDS: return STR_POSTFIELDS; case CURLOPT_PROXY: return STR_PROXY; case CURLOPT_PROXYUSERPWD: return STR_PROXYUSERPWD; case CURLOPT_RANDOM_FILE: return STR_RANDOM_FILE; case CURLOPT_RANGE: return STR_RANGE; case CURLOPT_REFERER: return STR_REFERER; case CURLOPT_SSLCERT: return STR_SSLCERT; case CURLOPT_SSLCERTPASSWD: return STR_SSLCERTPASSWD; case CURLOPT_SSLCERTTYPE: return STR_SSLCERTTYPE; case CURLOPT_SSLENGINE: return STR_SSLENGINE; case CURLOPT_SSLKEY: return STR_SSLKEY; case CURLOPT_SSLKEYTYPE: return STR_SSLKEYTYPE; case CURLOPT_SSL_CIPHER_LIST: return STR_SSL_CIPHER_LIST; case CURLOPT_URL: return STR_URL; case CURLOPT_USERAGENT: return STR_USERAGENT; case CURLOPT_USERPWD: return STR_USERPWD; #if CURL_NEWER(7,9,8) case CURLOPT_CAPATH: return STR_CAPATH; #endif #if CURL_NEWER(7,10,0) case CURLOPT_ENCODING: return STR_ENCODING; #endif #if CURL_NEWER(7,10,3) case CURLOPT_PRIVATE: return STR_PRIVATE; #endif #if CURL_NEWER(7,11,0) case CURLOPT_NETRC_FILE: return STR_NETRC_FILE; #endif default: L_error(L,"Unsupported string in bag"); } return 0; } /****************************************************************************** * checks and returns a string field from the first position in the stack * */ static char** L_checkcurlstring(lua_State*L,CURLoption opt) { struct L_curl_bag* tmp = (struct L_curl_bag*) luaL_checkudata(L,1,CURL_EASY_META_NAME); luaL_argcheck(L,tmp != NULL,1,"curleasy expected"); return &(tmp->strings[L_CURLoption2vect(L,opt)]); } /****************************************************************************** * checks and returns the header slist * */ static struct curl_slist ** L_checkcurlheadlist(lua_State*L) { struct L_curl_bag* tmp = (struct L_curl_bag*) luaL_checkudata(L,1,CURL_EASY_META_NAME); luaL_argcheck(L,tmp != NULL,1,"curleasy expected"); return &(tmp->headlist); } /****************************************************************************** * checks and returns the err field from the first position in the stack * */ static char* L_checkcurlerr(lua_State*L) { void* tmp = luaL_checkudata(L,1,CURL_EASY_META_NAME); luaL_argcheck(L,tmp != NULL,1,"curleasy expected"); return ((struct L_curl_bag*)tmp)->err; } /****************************************************************************** * checks and returns the post field from the first position in the stack * */ #if CURL_NEWER(7,9,6) static struct curl_httppost **L_checkcurlpost(lua_State*L){ void* tmp = luaL_checkudata(L,1,CURL_EASY_META_NAME); luaL_argcheck(L,tmp != NULL,1,"curleasy expected"); return &((struct L_curl_bag*)tmp)->post; } #endif /****************************************************************************** * checks if c is_in t and returns it * */ static long L_checkconst(lua_State* L, const struct L_const* t,const char* t_nam, int c){ int i,found; long int con; if( lua_type(L,c) != LUA_TNUMBER) L_error(L,"Expecting a %s value, got %s",t_nam, lua_typename(L,lua_type(L,c))); con = (long int)lua_tonumber(L,c); for ( i = 0,found = 0 ; t[i].name != NULL ; i++){ if( t[i].value == con){ found = 1; break; } } if(found == 1) return con; else { L_error(L,"Expecting a %s value, got something else",t_nam); } return -1; } /****************************************************************************** * checks if c is <= \sigma t and returns it * */ static long int L_checkconst_mask(lua_State* L, const struct L_const* t,const char* t_nam, int c){ int con; if( lua_type(L,c) != LUA_TNUMBER ) L_error(L,"Expecting a %s value, got nothing",t_nam); //FIXME: think a check con = (long int)lua_tonumber(L,c); return con; } /****************************************************************************** * checks, builds and return a string list * */ static struct curl_slist * L_checkslist(lua_State* L,int tab_index) { struct curl_slist * sl = NULL; /* since we manipulate the stack we want tab_index in absolute */ if ( tab_index < 0 ) tab_index = lua_gettop(L) + 1 + tab_index; /* a slist must be a LUA table */ luaL_argcheck(L,lua_istable(L,tab_index),tab_index,"expecting a table"); /* create the slist */ sl = NULL; /* traverse the table */ lua_pushnil(L); while( lua_next(L,tab_index) != 0 ){ const char * val; /* now we have: ...old_stack... | key:int | val:string */ if ( lua_type(L,-1) != LUA_TSTRING) { curl_slist_free_all(sl); L_error(L,"this table must be a string list"); } if ( lua_type(L,-2) != LUA_TNUMBER ) { curl_slist_free_all(sl); L_error(L,"this table is a list, keys must be unused"); } /* get the string */ val = lua_tostring(L,-1); /* pop val */ lua_pop(L,1); /* store it in the list */ sl = curl_slist_append(sl,val); } return sl; } /****************************************************************************** * curl_easy_perform * */ static int luacurl_easy_perform(lua_State* L) { CURL* c = L_checkcurleasy(L); CURLcode rc = curl_easy_perform(c); L_checknarg(L,1,"perform wants 1 argument (self)"); if ( rc == CURLE_OK ) { lua_pushnumber(L,(lua_Number)rc); lua_pushnil(L); }else{ lua_pushnumber(L,(lua_Number)rc); lua_pushstring(L,L_checkcurlerr(L)); } return 2; } /****************************************************************************** * curl write callback * */ static size_t L_callback_writedata( void *ptr,size_t size,size_t nmemb,void *stream){ lua_State* L = (lua_State*)stream; size_t rc; size_t dimension = size * nmemb; L_checknarg(L,1,"we expect the callback to have a curl handler on the stack"); /* find the lua closure */ /* XXX we assume the c:perform() leaves c on the stack */ lua_pushlightuserdata(L,CURL_WRITECB_OFF(L_checkcurleasy(L))); lua_rawget(L,LUA_REGISTRYINDEX); /* call it */ lua_pushlstring(L,(const char *)ptr,dimension); lua_pushnumber(L,dimension); lua_call(L,2,2); L_checknarg(L,3,"we expect the callback to return 2 arguments"); if (lua_type(L,-2) != LUA_TNUMBER) L_error(L,"head_cb must return: (number,errror_message or nil) but the " "first one is not a number"); rc = (size_t)lua_tonumber(L,-2); /* if( rc != dimension ) { if ( lua_type(L,-1) == LUA_TSTRING) L_error(L,"write_cb returned %d that is not the expected %d" ", error message: '%s'",rc,dimension,lua_tostring(L,-1)); else L_error(L,"write_cb returned %d that is not the expected %d" ", no error message",rc,dimension); } */ lua_pop(L,2); return rc; } /****************************************************************************** * curl write header callback * */ static size_t L_callback_writehead( void *ptr,size_t size,size_t nmemb,void *stream){ lua_State* L = (lua_State*)stream; size_t rc; size_t dimension = size * nmemb; L_checknarg(L,1,"we expect the callback to have a curl handler on the stack"); /* find the lua closure */ /* XXX we assume the c:perform() leaves c on the stack */ lua_pushlightuserdata(L,CURL_HEADCB_OFF(L_checkcurleasy(L))); lua_rawget(L,LUA_REGISTRYINDEX); /* call it */ lua_pushlstring(L,(const char *)ptr,dimension); lua_pushnumber(L,dimension); lua_call(L,2,2); L_checknarg(L,3,"we expect the callback to return 2 arguments"); if (lua_type(L,-2) != LUA_TNUMBER) L_error(L,"head_cb must return: (number,errror_message or nil) but the " "first one is not a number"); rc = (size_t)lua_tonumber(L,-2); /* if( rc != dimension ) { if ( lua_type(L,-1) == LUA_TSTRING) L_error(L,"head_cb returned %d that is not the expected %d" ", error message: '%s'",rc,dimension,lua_tostring(L,-1)); else L_error(L,"head_cb returned %d that is not the expected %d" ", no error message",rc,dimension); } */ lua_pop(L,2); return rc; } /****************************************************************************** * curl read callback * */ static size_t L_callback_readdata( void *ptr,size_t size,size_t nmemb,void *stream){ lua_State* L = (lua_State*)stream; size_t rc; size_t dimension = size * nmemb; L_checknarg(L,1,"we expect the callback to have a curl handler on the stack"); /* find the lua closure */ /* XXX we assume the c:perform() leaves c on the stack */ lua_pushlightuserdata(L,CURL_READCB_OFF(L_checkcurleasy(L))); lua_rawget(L,LUA_REGISTRYINDEX); /* call it */ lua_pushnumber(L,dimension); lua_call(L,1,2); L_checknarg(L,3,"we expect the callback to return 2 arguments"); if (lua_type(L,-2) != LUA_TNUMBER) L_error(L,"read_cb must return: (number,errror_message or nil) but the " "first one is not a number"); rc = (size_t)lua_tonumber(L,-2); if(rc != 0) { /* we have data to send */ if ( rc > dimension ) L_error(L,"read_rc must return a size <= than the number " "that received in input"); if ( lua_type(L,-1) != LUA_TSTRING) L_error(L,"read_cb must return a string as the second " "value, not a %s",lua_typename(L,lua_type(L,-1))); if ( rc != lua_strlen(L,-1) ) L_error(L,"read_cb must return a size and a string, " "and the size must be the string size"); memcpy(ptr,lua_tostring(L,-1),rc); } lua_pop(L,2); return rc; } /****************************************************************************** * CURLOPT_HTTPPOST parser * */ #if CURL_NEWER(7,9,8) static CURLcode L_httppost(CURL* c,CURLoption opt,lua_State* L){ /* we assume we hve stack: || c | opt | table * * table is a table of tables since we assume the function is called: * c:setopt(curl.OPT_HTTPPOST,{ * {curl.FORM_COPYNAME,"name1", * curl.FORM_COPYCONTENTS,"data1", * curl.FORM_CONTENTTYPE,"Content-type: text/plain", * curl.FORM_END}, * {curl.FORM_COPYNAME,"name2", * curl.FORM_COPYCONTENTS,"data2", * curl.FORM_CONTENTTYPE,"Content-type: text/plain", * curl.FORM_END} * }) * */ struct curl_httppost *post = NULL, *last = NULL; #if CURL_NEWER(7,9,8) CURLFORMcode rc = CURL_FORMADD_OK; #else int rc = CURL_FORMADD_OK; #endif CURLcode rc_opt = CURLE_OK; /* check for the table */ if( ! lua_istable(L,3) ) L_error(L,"expecting a table, got %s",lua_typename(L,lua_type(L,3))); /* outer loop to travers the table list */ lua_pushnil(L); while( lua_next(L,3) != 0 ){ /* now we have: ...old_stack... | key:int | val:table * and we traverse the internal table */ int forms_size = L_tablesize(L,5)/2+1; struct curl_forms forms[forms_size]; /* not ANSI */ int position = 0; lua_pushnil(L); while( lua_next(L,5) != 0 ){ CURLformoption o = (CURLformoption) L_checkconst(L,curl_easy_form_c,"CURLformoption",7); switch(o){ case CURLFORM_BUFFER: case CURLFORM_BUFFERPTR: case CURLFORM_FILENAME: case CURLFORM_CONTENTTYPE: /* sould be ok */ case CURLFORM_FILE: case CURLFORM_FILECONTENT: case CURLFORM_PTRCONTENTS: case CURLFORM_COPYCONTENTS: case CURLFORM_PTRNAME: case CURLFORM_COPYNAME:{ forms[position].option = o; lua_pop(L,1); if(lua_next(L,5) == 0) L_error(L, "incomplete FORM, value missed"); forms[position].value = luaL_checkstring(L,7); }break; case CURLFORM_BUFFERLENGTH:{ forms[position].option = o; lua_pop(L,1); if(lua_next(L,5) == 0) L_error(L, "incomplete FORM, value missed"); forms[position].value = (char*) #ifdef __UWORD_TYPE (__UWORD_TYPE) #endif //not sure this makes sense luaL_checkint(L,7); }break; case CURLFORM_CONTENTHEADER:{ /* we need a damned bag here! */ L_error(L,"not implemented, use " "CURLFORM_CONTENTTYPE instead"); }break; case CURLFORM_END:{ forms[position].option = o; }break; case CURLFORM_ARRAY:{ L_error(L,"You can't use CURLFORM_ARRAY"); }break; default:{ L_error(L,"invalid CURLFORM_"); }break; } position++; lua_pop(L,1); } if ( (positionhandler = tmp; for(i = 0 ; i < STR_SIZE ; i++) c->strings[i] = NULL; c->headlist = NULL; #if CURL_NEWER(7,9,6) c->post=NULL; #endif rc = curl_easy_setopt(tmp,CURLOPT_ERRORBUFFER,c->err); /* check for errors */ if( rc != CURLE_OK) { L_error(L,"unable to call CURLOPT_ERRORBUFFER (%d)",rc); } return 1; } /****************************************************************************** * curl_easy_cleanup * */ static int luacurl_easy_cleanup(lua_State* L) { struct L_curl_bag* c = L_checkcurluserdata(L); int i; curl_easy_cleanup(c->handler); for(i = 0 ; i < STR_SIZE ; i++) free(c->strings[i]); curl_slist_free_all(c->headlist); #if CURL_NEWER(7,9,6) if(c->post != NULL) curl_formfree(c->post); #endif lua_pushlightuserdata(L,CURL_WRITECB_OFF(c)); lua_pushnil(L); lua_rawset(L,LUA_REGISTRYINDEX); lua_pushlightuserdata(L,CURL_READCB_OFF(c)); lua_pushnil(L); lua_rawset(L,LUA_REGISTRYINDEX); lua_pushlightuserdata(L,CURL_HEADCB_OFF(c)); lua_pushnil(L); lua_rawset(L,LUA_REGISTRYINDEX); return 0; } /****************************************************************************** * curl_escape * */ static int luacurl_escape(lua_State* L) { const char* data = luaL_checkstring(L,1); size_t len = lua_strlen(L,1); char * tmp; L_checknarg(L,1,"escape wants 1 argument (string)"); tmp = curl_escape(data,len); lua_pushstring(L,tmp); #if CURL_NEWER(7,10,0) curl_free(tmp); #else free(tmp); #endif return 1; } /****************************************************************************** * curl_unescape * */ static int luacurl_unescape(lua_State* L) { const char* data = luaL_checkstring(L,1); size_t len = lua_strlen(L,1); char * tmp; L_checknarg(L,1,"unescape wants 1 argument (string)"); tmp = curl_unescape(data,len); lua_pushstring(L,tmp); #if CURL_NEWER(7,10,0) curl_free(tmp); #else free(tmp); #endif return 1; } /****************************************************************************** * curl_version * */ static int luacurl_version(lua_State* L) { L_checknarg(L,0,"version wants no arguments"); lua_pushstring(L,curl_version()); return 1; } /****************************************************************************** * curl_version_info * */ #if CURL_NEWER(7,10,0) static int luacurl_version_info(lua_State* L) { curl_version_info_data *d = curl_version_info(CURLVERSION_NOW); int i; L_checknarg(L,0,"version_info wants no arguments"); lua_newtable(L); lua_pushstring(L,"version"); lua_pushstring(L,d->version); lua_settable(L,-3); lua_pushstring(L,"version_num"); lua_pushnumber(L,d->version_num); lua_settable(L,-3); lua_pushstring(L,"host"); lua_pushstring(L,d->host); lua_settable(L,-3); lua_pushstring(L,"ssl_version"); lua_pushstring(L,d->ssl_version); lua_settable(L,-3); lua_pushstring(L,"ssl_version_num"); lua_pushnumber(L,d->ssl_version_num); lua_settable(L,-3); lua_pushstring(L,"features"); lua_pushnumber(L,d->features); lua_settable(L,-3); lua_pushstring(L,"libz_version"); lua_pushstring(L,d->libz_version); lua_settable(L,-3); lua_pushstring(L,"protocols"); lua_newtable(L); for(i=0;d->protocols[i] != NULL;i++){ lua_pushnumber(L,i+1); lua_pushstring(L,d->protocols[i]); lua_settable(L,-3); } lua_pushstring(L,"n"); lua_pushnumber(L,i); lua_settable(L,-3); lua_settable(L,-3); return 1; } #endif /****************************************************************************** * curl.* functions * */ static const struct luaL_reg curl_f [] = { {"easy_init",luacurl_easy_init}, {"escape",luacurl_escape}, {"unescape",luacurl_unescape}, {"version",luacurl_version}, #if CURL_NEWER(7,10,0) {"version_info",luacurl_version_info}, #endif {NULL,NULL} }; /****************************************************************************** * c:* functions * */ static const struct luaL_reg curl_easy_m [] = { {"setopt",luacurl_easy_setopt}, {"perform",luacurl_easy_perform}, {NULL,NULL} }; /****************************************************************************** * open the luacurl library * you need to call curl_global_init manually * */ int luacurl_open(lua_State* L) { luaL_newmetatable(L,CURL_EASY_META_NAME); lua_pushstring(L,"__gc"); lua_pushcfunction(L,luacurl_easy_cleanup); lua_settable(L,-3); lua_pushstring(L,"__index"); lua_pushvalue(L,-2); lua_settable(L,-3); luaL_openlib(L,NULL,curl_easy_m,0); luaL_openlib(L,"curl",curl_f,0); L_openconst(L,curl_easy_c); #if CURL_NEWER(7,9,8) L_openconst(L,curl_easy_netrc_c); #endif #if CURL_NEWER(7,10,6) L_openconst(L,curl_easy_auth_c); #endif L_openconst(L,curl_easy_httpver_c); L_openconst(L,curl_easy_form_c); #if CURL_NEWER(7,11,0) L_openconst(L,curl_easy_ftpssl_c); #endif L_openconst(L,curl_easy_closepolicy_c); #if CURL_NEWER(7,10,8) L_openconst(L,curl_easy_ipresolve_c); #endif #if CURL_NEWER(7,10,0) L_openconst(L,curl_easy_proxytype_c); #endif return 1; } /****************************************************************************** * opens the luacurl library and calls curl_global_init(CURL_GLOBAL_ALL) * use this if you have not initialized cURL in the C code * */ int luacurl_open_and_init(lua_State* L) { curl_global_init(CURL_GLOBAL_ALL); return luacurl_open(L); }