742 lines
19 KiB
C
742 lines
19 KiB
C
#include "lcurl.h"
|
|
#include "lceasy.h"
|
|
#include "lcerror.h"
|
|
#include "lcutils.h"
|
|
#include "lchttppost.h"
|
|
#include "lcshare.h"
|
|
|
|
static const char *LCURL_ERROR_TAG = "LCURL_ERROR_TAG";
|
|
|
|
#define LCURL_EASY_NAME LCURL_PREFIX" Easy"
|
|
static const char *LCURL_EASY = LCURL_EASY_NAME;
|
|
|
|
//{
|
|
|
|
int lcurl_easy_create(lua_State *L, int error_mode){
|
|
lcurl_easy_t *p = lutil_newudatap(L, lcurl_easy_t, LCURL_EASY);
|
|
int i;
|
|
p->curl = curl_easy_init();
|
|
p->err_mode = error_mode;
|
|
if(!p->curl) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_FAILED_INIT);
|
|
p->L = L;
|
|
p->storage = lcurl_storage_init(L);
|
|
p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF;
|
|
p->rd.cb_ref = p->rd.ud_ref = LUA_NOREF;
|
|
p->hd.cb_ref = p->hd.ud_ref = LUA_NOREF;
|
|
p->pr.cb_ref = p->pr.ud_ref = LUA_NOREF;
|
|
p->rbuffer.ref = LUA_NOREF;
|
|
for(i = 0; i < LCURL_LIST_COUNT; ++i){
|
|
p->lists[i] = LUA_NOREF;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
lcurl_easy_t *lcurl_geteasy_at(lua_State *L, int i){
|
|
lcurl_easy_t *p = (lcurl_easy_t *)lutil_checkudatap (L, i, LCURL_EASY);
|
|
luaL_argcheck (L, p != NULL, 1, LCURL_EASY_NAME" expected");
|
|
return p;
|
|
}
|
|
|
|
static int lcurl_easy_cleanup(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
int i;
|
|
|
|
if(p->curl){
|
|
curl_easy_cleanup(p->curl);
|
|
p->curl = NULL;
|
|
}
|
|
|
|
if(p->storage != LUA_NOREF){
|
|
p->storage = lcurl_storage_free(L, p->storage);
|
|
}
|
|
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->wr.cb_ref);
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->wr.ud_ref);
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->rd.cb_ref);
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->rd.ud_ref);
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->pr.cb_ref);
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->pr.ud_ref);
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->hd.cb_ref);
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->hd.ud_ref);
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref);
|
|
|
|
p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF;
|
|
p->rd.cb_ref = p->rd.ud_ref = LUA_NOREF;
|
|
p->hd.cb_ref = p->hd.ud_ref = LUA_NOREF;
|
|
p->pr.cb_ref = p->pr.ud_ref = LUA_NOREF;
|
|
p->rbuffer.ref = LUA_NOREF;
|
|
|
|
for(i = 0; i < LCURL_LIST_COUNT; ++i){
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->lists[i]);
|
|
p->lists[i] = LUA_NOREF;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int lcurl_easy_perform(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
CURLcode code;
|
|
int top = 1;
|
|
lua_settop(L, top);
|
|
|
|
assert(p->rbuffer.ref == LUA_NOREF);
|
|
|
|
code = curl_easy_perform(p->curl);
|
|
|
|
if(p->rbuffer.ref != LUA_NOREF){
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref);
|
|
p->rbuffer.ref = LUA_NOREF;
|
|
}
|
|
|
|
if(code == CURLE_OK){
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
if((lua_gettop(L) > top)&&(lua_touserdata(L, top + 1) == LCURL_ERROR_TAG)){
|
|
return lua_error(L);
|
|
}
|
|
|
|
if(code == CURLE_WRITE_ERROR){
|
|
if(lua_gettop(L) > top){
|
|
return lua_gettop(L) - top;
|
|
}
|
|
}
|
|
|
|
if(code == CURLE_ABORTED_BY_CALLBACK){
|
|
if(lua_gettop(L) > top){
|
|
return lua_gettop(L) - top;
|
|
}
|
|
}
|
|
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
|
|
static int lcurl_easy_escape(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
size_t data_size; const char *data = luaL_checklstring(L, 2, &data_size);
|
|
const char *ret = curl_easy_escape(p->curl, data, (int)data_size);
|
|
if(!ret){
|
|
lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_OUT_OF_MEMORY);
|
|
}
|
|
lua_pushstring(L, ret);
|
|
curl_free((char*)ret);
|
|
return 1;
|
|
}
|
|
|
|
static int lcurl_easy_unescape(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
size_t data_size; const char *data = luaL_checklstring(L, 2, &data_size);
|
|
int ret_size; const char *ret = curl_easy_unescape(p->curl, data, (int)data_size, &ret_size);
|
|
if(!ret){
|
|
lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_OUT_OF_MEMORY);
|
|
}
|
|
lua_pushlstring(L, ret, ret_size);
|
|
curl_free((char*)ret);
|
|
return 1;
|
|
}
|
|
|
|
static int lcurl_easy_reset(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
curl_easy_reset(p->curl);
|
|
lua_settop(L, 1);
|
|
|
|
if(p->storage != LUA_NOREF){
|
|
lcurl_storage_free(L, p->storage);
|
|
p->storage = lcurl_storage_init(L);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//{ OPTIONS
|
|
|
|
static int lcurl_opt_set_long_(lua_State *L, int opt){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
long val; CURLcode code;
|
|
|
|
if(lua_isboolean(L, 2)) val = lua_toboolean(L, 2);
|
|
else{
|
|
luaL_argcheck(L, lua_type(L, 2) == LUA_TNUMBER, 2, "number or boolean expected");
|
|
val = luaL_checklong(L, 2);
|
|
}
|
|
|
|
code = curl_easy_setopt(p->curl, opt, val);
|
|
if(code != CURLE_OK){
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int lcurl_opt_set_string_(lua_State *L, int opt, int store){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
CURLcode code;
|
|
|
|
luaL_argcheck(L, lua_type(L, 2) == LUA_TSTRING, 2, "string expected");
|
|
|
|
code = curl_easy_setopt(p->curl, opt, lua_tostring(L, 2));
|
|
if(code != CURLE_OK){
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
|
|
if(store)lcurl_storage_preserve_value(L, p->storage, 2);
|
|
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int lcurl_opt_set_slist_(lua_State *L, int opt, int list_no){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
struct curl_slist *list = lcurl_util_to_slist(L, 2);
|
|
CURLcode code;
|
|
int ref = p->lists[list_no];
|
|
|
|
luaL_argcheck(L, list, 2, "array expected");
|
|
|
|
if(ref != LUA_NOREF){
|
|
struct curl_slist *tmp = lcurl_storage_remove_slist(L, p->storage, ref);
|
|
curl_slist_free_all(tmp);
|
|
p->lists[list_no] = LUA_NOREF;
|
|
}
|
|
|
|
code = curl_easy_setopt(p->curl, opt, list);
|
|
|
|
if(code != CURLE_OK){
|
|
curl_slist_free_all(list);
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
|
|
p->lists[list_no] = lcurl_storage_preserve_slist(L, p->storage, list);
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
#define LCURL_STR_OPT(N, S) static int lcurl_easy_set_##N(lua_State *L){\
|
|
return lcurl_opt_set_string_(L, CURLOPT_##N, (S)); \
|
|
}
|
|
|
|
#define LCURL_LST_OPT(N, S) static int lcurl_easy_set_##N(lua_State *L){\
|
|
return lcurl_opt_set_slist_(L, CURLOPT_##N, LCURL_##N##_LIST);\
|
|
}
|
|
|
|
#define LCURL_LNG_OPT(N, S) static int lcurl_easy_set_##N(lua_State *L){\
|
|
return lcurl_opt_set_long_(L, CURLOPT_##N);\
|
|
}
|
|
|
|
#define OPT_ENTRY(L, N, T, S) LCURL_##T##_OPT(N, S)
|
|
|
|
#include "lcopteasy.h"
|
|
|
|
#undef OPT_ENTRY
|
|
|
|
static int lcurl_easy_set_POSTFIELDS(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
size_t len; const char *val = luaL_checklstring(L, 2, &len);
|
|
CURLcode code;
|
|
if(lua_isnumber(L, 3)){
|
|
size_t n = (size_t)lua_tonumber(L, 3);
|
|
luaL_argcheck(L, len <= n, 3, "data length too big");
|
|
len = n;
|
|
}
|
|
code = curl_easy_setopt(p->curl, CURLOPT_POSTFIELDS, val);
|
|
if(code != CURLE_OK){
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
lcurl_storage_preserve_value(L, p->storage, 2);
|
|
code = curl_easy_setopt(p->curl, CURLOPT_POSTFIELDSIZE, (long)len);
|
|
if(code != CURLE_OK){
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
#undef LCURL_STR_OPT
|
|
#undef LCURL_LST_OPT
|
|
#undef LCURL_LNG_OPT
|
|
|
|
static int lcurl_easy_set_HTTPPOST(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
lcurl_hpost_t *post = lcurl_gethpost_at(L, 2);
|
|
CURLcode code = curl_easy_setopt(p->curl, CURLOPT_HTTPPOST, post->post);
|
|
if(code != CURLE_OK){
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
|
|
lcurl_storage_preserve_value(L, p->storage, 2);
|
|
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int lcurl_easy_set_SHARE(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
lcurl_share_t *sh = lcurl_getshare_at(L, 2);
|
|
CURLcode code = curl_easy_setopt(p->curl, CURLOPT_SHARE, sh->curl);
|
|
if(code != CURLE_OK){
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
|
|
lcurl_storage_preserve_value(L, p->storage, 2);
|
|
|
|
lua_settop(L, 1);
|
|
return 1;
|
|
}
|
|
|
|
//}
|
|
|
|
//{ info
|
|
|
|
static int lcurl_info_get_long_(lua_State *L, int opt){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
long val; CURLcode code;
|
|
|
|
code = curl_easy_getinfo(p->curl, opt, &val);
|
|
if(code != CURLE_OK){
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
|
|
lua_pushnumber(L, val);
|
|
return 1;
|
|
}
|
|
|
|
static int lcurl_info_get_double_(lua_State *L, int opt){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
double val; CURLcode code;
|
|
|
|
code = curl_easy_getinfo(p->curl, opt, &val);
|
|
if(code != CURLE_OK){
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
|
|
lua_pushnumber(L, val);
|
|
return 1;
|
|
}
|
|
|
|
static int lcurl_info_get_string_(lua_State *L, int opt){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
char *val; CURLcode code;
|
|
|
|
code = curl_easy_getinfo(p->curl, opt, &val);
|
|
if(code != CURLE_OK){
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
|
|
lua_pushstring(L, val);
|
|
return 1;
|
|
}
|
|
|
|
static int lcurl_info_get_slist_(lua_State *L, int opt){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
struct curl_slist *val; CURLcode code;
|
|
|
|
code = curl_easy_getinfo(p->curl, opt, &val);
|
|
if(code != CURLE_OK){
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, code);
|
|
}
|
|
|
|
lcurl_util_slist_to_table(L, val);
|
|
curl_slist_free_all(val);
|
|
|
|
return 1;
|
|
}
|
|
|
|
#define LCURL_STR_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\
|
|
return lcurl_info_get_string_(L, CURLINFO_##N); \
|
|
}
|
|
|
|
#define LCURL_LST_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\
|
|
return lcurl_info_get_slist_(L, CURLINFO_##N);\
|
|
}
|
|
|
|
#define LCURL_LNG_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\
|
|
return lcurl_info_get_long_(L, CURLINFO_##N);\
|
|
}
|
|
|
|
#define LCURL_DBL_INFO(N, S) static int lcurl_easy_get_##N(lua_State *L){\
|
|
return lcurl_info_get_double_(L, CURLINFO_##N);\
|
|
}
|
|
|
|
#define OPT_ENTRY(L, N, T, S) LCURL_##T##_INFO(N, S)
|
|
|
|
#include "lcinfoeasy.h"
|
|
|
|
#undef OPT_ENTRY
|
|
|
|
#undef LCURL_STR_INFO
|
|
#undef LCURL_LST_INFO
|
|
#undef LCURL_LNG_INFO
|
|
#undef LCURL_DBL_INFO
|
|
|
|
//}
|
|
|
|
//{ CallBack
|
|
|
|
static int lcurl_easy_set_callback(lua_State *L,
|
|
lcurl_easy_t *p, lcurl_callback_t *c,
|
|
int OPT_CB, int OPT_UD,
|
|
const char *method, void *func
|
|
)
|
|
{
|
|
if(c->ud_ref != LUA_NOREF){
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, c->ud_ref);
|
|
c->ud_ref = LUA_NOREF;
|
|
}
|
|
|
|
if(c->cb_ref != LUA_NOREF){
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, c->cb_ref);
|
|
c->cb_ref = LUA_NOREF;
|
|
}
|
|
|
|
if(lua_gettop(L) >= 3){// function + context
|
|
lua_settop(L, 3);
|
|
luaL_argcheck(L, !lua_isnil(L, 2), 2, "no function present");
|
|
c->ud_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
|
|
c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
|
|
|
|
curl_easy_setopt(p->curl, OPT_UD, p);
|
|
curl_easy_setopt(p->curl, OPT_CB, func);
|
|
|
|
assert(1 == lua_gettop(L));
|
|
return 1;
|
|
}
|
|
|
|
lua_settop(L, 2);
|
|
|
|
if(lua_isnoneornil(L, 2)){
|
|
lua_pop(L, 1);
|
|
assert(1 == lua_gettop(L));
|
|
|
|
curl_easy_setopt(p->curl, OPT_UD, 0);
|
|
curl_easy_setopt(p->curl, OPT_CB, 0);
|
|
|
|
return 1;
|
|
}
|
|
|
|
if(lua_isfunction(L, 2)){
|
|
c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
|
|
assert(1 == lua_gettop(L));
|
|
|
|
curl_easy_setopt(p->curl, OPT_UD, p);
|
|
curl_easy_setopt(p->curl, OPT_CB, func);
|
|
return 1;
|
|
}
|
|
|
|
if(lua_isuserdata(L, 2) || lua_istable(L, 2)){
|
|
lua_getfield(L, 2, method);
|
|
luaL_argcheck(L, lua_isfunction(L, -1), 2, "method not found in object");
|
|
c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
|
|
c->ud_ref = luaL_ref(L, LCURL_LUA_REGISTRY);
|
|
curl_easy_setopt(p->curl, OPT_UD, p);
|
|
curl_easy_setopt(p->curl, OPT_CB, func);
|
|
assert(1 == lua_gettop(L));
|
|
return 1;
|
|
}
|
|
|
|
lua_pushliteral(L, "invalid object type");
|
|
return lua_error(L);
|
|
}
|
|
|
|
static int lcurl_write_callback_(lua_State*L,
|
|
lcurl_easy_t *p, lcurl_callback_t *c,
|
|
char *ptr, size_t size, size_t nmemb
|
|
){
|
|
|
|
size_t ret = size * nmemb;
|
|
int top = lua_gettop(L);
|
|
int n = lcurl_util_push_cb(L, c);
|
|
|
|
lua_pushlstring(L, ptr, ret);
|
|
if(lua_pcall(L, n, LUA_MULTRET, 0)){
|
|
assert(lua_gettop(L) >= top);
|
|
lua_pushlightuserdata(L, (void*)LCURL_ERROR_TAG);
|
|
lua_insert(L, top+1);
|
|
return 0;
|
|
}
|
|
|
|
if(lua_gettop(L) > top){
|
|
if(lua_isnil(L, top + 1)) return 0;
|
|
if(lua_isboolean(L, top + 1)){
|
|
if(!lua_toboolean(L, top + 1)) ret = 0;
|
|
}
|
|
else ret = (size_t)lua_tonumber(L, top + 1);
|
|
}
|
|
|
|
lua_settop(L, top);
|
|
return ret;
|
|
}
|
|
|
|
//{ Writer
|
|
|
|
static int lcurl_write_callback(char *ptr, size_t size, size_t nmemb, void *arg){
|
|
lcurl_easy_t *p = arg;
|
|
return lcurl_write_callback_(p->L, p, &p->wr, ptr, size, nmemb);
|
|
}
|
|
|
|
static int lcurl_easy_set_WRITEFUNCTION(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
return lcurl_easy_set_callback(L, p, &p->wr,
|
|
CURLOPT_WRITEFUNCTION, CURLOPT_WRITEDATA,
|
|
"write", lcurl_write_callback
|
|
);
|
|
}
|
|
|
|
//}
|
|
|
|
//{ Reader
|
|
|
|
static int lcurl_read_callback(char *buffer, size_t size, size_t nitems, void *arg){
|
|
lcurl_easy_t *p = arg;
|
|
lua_State *L = p->L;
|
|
|
|
const char *data; size_t data_size;
|
|
|
|
size_t ret = size * nitems;
|
|
int n, top = lua_gettop(L);
|
|
|
|
if(p->rbuffer.ref != LUA_NOREF){
|
|
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->rbuffer.ref);
|
|
data = luaL_checklstring(L, -1, &data_size);
|
|
lua_pop(L, 1);
|
|
|
|
data = data + p->rbuffer.off;
|
|
data_size -= p->rbuffer.off;
|
|
|
|
if(data_size > ret){
|
|
data_size = ret;
|
|
memcpy(buffer, data, data_size);
|
|
p->rbuffer.off += data_size;
|
|
}
|
|
else{
|
|
memcpy(buffer, data, data_size);
|
|
luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref);
|
|
p->rbuffer.ref = LUA_NOREF;
|
|
}
|
|
|
|
lua_settop(L, top);
|
|
return data_size;
|
|
}
|
|
|
|
// buffer is clean
|
|
assert(p->rbuffer.ref == LUA_NOREF);
|
|
|
|
n = lcurl_util_push_cb(L, &p->rd);
|
|
lua_pushnumber(L, ret);
|
|
if(lua_pcall(L, n, LUA_MULTRET, 0)) return CURL_READFUNC_ABORT;
|
|
|
|
if(lua_isnoneornil(L, top + 1)){
|
|
if(lua_gettop(L) <= (top + 1))return 0;
|
|
return CURL_READFUNC_ABORT;
|
|
}
|
|
data = lua_tolstring(L, -1, &data_size);
|
|
if(!data) return CURL_READFUNC_ABORT;
|
|
|
|
if(data_size > ret){
|
|
data_size = ret;
|
|
p->rbuffer.ref = luaL_ref(L, LCURL_LUA_REGISTRY);
|
|
p->rbuffer.off = data_size;
|
|
}
|
|
memcpy(buffer, data, data_size);
|
|
|
|
lua_settop(L, top);
|
|
return data_size;
|
|
}
|
|
|
|
static int lcurl_easy_set_READFUNCTION(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
return lcurl_easy_set_callback(L, p, &p->rd,
|
|
CURLOPT_READFUNCTION, CURLOPT_READDATA,
|
|
"read", lcurl_read_callback
|
|
);
|
|
}
|
|
|
|
//}
|
|
|
|
//{ Header
|
|
|
|
static int lcurl_header_callback(char *ptr, size_t size, size_t nmemb, void *arg){
|
|
lcurl_easy_t *p = arg;
|
|
return lcurl_write_callback_(p->L, p, &p->hd, ptr, size, nmemb);
|
|
}
|
|
|
|
static int lcurl_easy_set_HEADERFUNCTION(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
return lcurl_easy_set_callback(L, p, &p->hd,
|
|
CURLOPT_HEADERFUNCTION, CURLOPT_HEADERDATA,
|
|
"header", lcurl_header_callback
|
|
);
|
|
}
|
|
|
|
//}
|
|
|
|
//{ Progress
|
|
|
|
static int lcurl_xferinfo_callback(void *arg, curl_off_t dltotal, curl_off_t dlnow,
|
|
curl_off_t ultotal, curl_off_t ulnow)
|
|
{
|
|
lcurl_easy_t *p = arg;
|
|
lua_State *L = p->L;
|
|
|
|
int ret = 0;
|
|
int top = lua_gettop(L);
|
|
int n = lcurl_util_push_cb(L, &p->pr);
|
|
|
|
lua_pushnumber( L, (lua_Number)dltotal );
|
|
lua_pushnumber( L, (lua_Number)dlnow );
|
|
lua_pushnumber( L, (lua_Number)ultotal );
|
|
lua_pushnumber( L, (lua_Number)ulnow );
|
|
|
|
if(lua_pcall(L, n+3, LUA_MULTRET, 0)){
|
|
assert(lua_gettop(L) >= top);
|
|
lua_pushlightuserdata(L, (void*)LCURL_ERROR_TAG);
|
|
lua_insert(L, top+1);
|
|
return 0;
|
|
}
|
|
|
|
if(lua_gettop(L) > top){
|
|
if(lua_isnil(L, top + 1)) return 1;
|
|
if(lua_isboolean(L, top + 1))
|
|
ret = lua_toboolean(L, top + 1)?0:1;
|
|
else ret = (size_t)lua_tonumber(L, top + 1);
|
|
}
|
|
|
|
lua_settop(L, top);
|
|
return ret;
|
|
}
|
|
|
|
static int lcurl_progress_callback(void *arg, double dltotal, double dlnow,
|
|
double ultotal, double ulnow)
|
|
{
|
|
return lcurl_xferinfo_callback(arg,
|
|
(curl_off_t)dltotal,
|
|
(curl_off_t)dlnow,
|
|
(curl_off_t)ultotal,
|
|
(curl_off_t)ulnow
|
|
);
|
|
}
|
|
|
|
static int lcurl_easy_set_PROGRESSFUNCTION(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
int n = lcurl_easy_set_callback(L, p, &p->pr,
|
|
CURLOPT_PROGRESSFUNCTION, CURLOPT_PROGRESSDATA,
|
|
"progress", lcurl_progress_callback
|
|
);
|
|
|
|
#if LCURL_CURL_VER_GE(7,32,0)
|
|
if(p->pr.cb_ref != LUA_NOREF){
|
|
CURLcode code;
|
|
code = curl_easy_setopt(p->curl, CURLOPT_XFERINFOFUNCTION, lcurl_xferinfo_callback);
|
|
code = curl_easy_setopt(p->curl, CURLOPT_XFERINFODATA, p);
|
|
}
|
|
#endif
|
|
|
|
return n;
|
|
}
|
|
|
|
//}
|
|
|
|
//}
|
|
|
|
static int lcurl_easy_setopt(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
int opt = luaL_checklong(L, 2);
|
|
lua_remove(L, 2);
|
|
|
|
#define OPT_ENTRY(l, N, T, S) case CURLOPT_##N: return lcurl_easy_set_##N(L);
|
|
switch(opt){
|
|
#include "lcopteasy.h"
|
|
OPT_ENTRY(postfields, POSTFIELDS, TTT, 0)
|
|
OPT_ENTRY(httppost, HTTPPOST, TTT, 0)
|
|
OPT_ENTRY(share, SHARE, TTT, 0)
|
|
OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0)
|
|
OPT_ENTRY(readfunction, READFUNCTION, TTT, 0)
|
|
OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0)
|
|
OPT_ENTRY(progressfunction, PROGRESSFUNCTION, TTT, 0)
|
|
}
|
|
#undef OPT_ENTRY
|
|
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY,
|
|
#if LCURL_CURL_VER_GE(7,21,5)
|
|
CURLE_UNKNOWN_OPTION
|
|
#else
|
|
CURLE_UNKNOWN_TELNET_OPTION
|
|
#endif
|
|
);
|
|
}
|
|
|
|
static int lcurl_easy_getinfo(lua_State *L){
|
|
lcurl_easy_t *p = lcurl_geteasy(L);
|
|
int opt = luaL_checklong(L, 2);
|
|
lua_remove(L, 2);
|
|
|
|
#define OPT_ENTRY(l, N, T, S) case CURLINFO_##N: return lcurl_easy_get_##N(L);
|
|
switch(opt){
|
|
#include "lcinfoeasy.h"
|
|
}
|
|
#undef OPT_ENTRY
|
|
|
|
return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_UNKNOWN_OPTION);
|
|
}
|
|
|
|
//}
|
|
|
|
static const struct luaL_Reg lcurl_easy_methods[] = {
|
|
|
|
#define OPT_ENTRY(L, N, T, S) { "setopt_"#L, lcurl_easy_set_##N },
|
|
#include "lcopteasy.h"
|
|
OPT_ENTRY(postfields, POSTFIELDS, TTT, 0)
|
|
OPT_ENTRY(httppost, HTTPPOST, TTT, 0)
|
|
OPT_ENTRY(share, SHARE, TTT, 0)
|
|
OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0)
|
|
OPT_ENTRY(readfunction, READFUNCTION, TTT, 0)
|
|
OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0)
|
|
OPT_ENTRY(progressfunction, PROGRESSFUNCTION, TTT, 0)
|
|
#undef OPT_ENTRY
|
|
|
|
#define OPT_ENTRY(L, N, T, S) { "getinfo_"#L, lcurl_easy_get_##N },
|
|
#include "lcinfoeasy.h"
|
|
#undef OPT_ENTRY
|
|
|
|
{ "reset", lcurl_easy_reset },
|
|
{ "setopt", lcurl_easy_setopt },
|
|
{ "getinfo", lcurl_easy_getinfo },
|
|
{ "escape", lcurl_easy_escape },
|
|
{ "unescape", lcurl_easy_unescape },
|
|
{ "perform", lcurl_easy_perform },
|
|
{ "close", lcurl_easy_cleanup },
|
|
{ "__gc", lcurl_easy_cleanup },
|
|
|
|
{NULL,NULL}
|
|
};
|
|
|
|
static const lcurl_const_t lcurl_easy_opt[] = {
|
|
|
|
#define OPT_ENTRY(L, N, T, S) { "OPT_"#N, CURLOPT_##N },
|
|
#define FLG_ENTRY(N) { #N, CURL_##N },
|
|
#include "lcopteasy.h"
|
|
OPT_ENTRY(postfields, POSTFIELDS, TTT, 0)
|
|
OPT_ENTRY(httppost, HTTPPOST, TTT, 0)
|
|
OPT_ENTRY(share, SHARE, TTT, 0)
|
|
OPT_ENTRY(writefunction, WRITEFUNCTION, TTT, 0)
|
|
OPT_ENTRY(readfunction, READFUNCTION, TTT, 0)
|
|
OPT_ENTRY(headerfunction, HEADERFUNCTION, TTT, 0)
|
|
OPT_ENTRY(progressfunction, PROGRESSFUNCTION, TTT, 0)
|
|
#undef OPT_ENTRY
|
|
#undef FLG_ENTRY
|
|
|
|
#define OPT_ENTRY(L, N, T, S) { "INFO_"#N, CURLINFO_##N },
|
|
#include "lcinfoeasy.h"
|
|
#undef OPT_ENTRY
|
|
|
|
{NULL, 0}
|
|
};
|
|
|
|
void lcurl_easy_initlib(lua_State *L, int nup){
|
|
if(!lutil_createmetap(L, LCURL_EASY, lcurl_easy_methods, nup))
|
|
lua_pop(L, nup);
|
|
lua_pop(L, 1);
|
|
|
|
lcurl_util_set_const(L, lcurl_easy_opt);
|
|
} |