diff --git a/src/lceasy.c b/src/lceasy.c index 3c3d9e1..893f115 100644 --- a/src/lceasy.c +++ b/src/lceasy.c @@ -277,6 +277,8 @@ static int lcurl_easy_set_POSTFIELDS(lua_State *L){ #undef LCURL_LST_OPT #undef LCURL_LNG_OPT +static int lcurl_hpost_read_callback(char *buffer, size_t size, size_t nitems, void *arg); + 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); @@ -287,6 +289,10 @@ static int lcurl_easy_set_HTTPPOST(lua_State *L){ lcurl_storage_preserve_iv(L, p->storage, CURLOPT_HTTPPOST, 2); + if(post->stream){ + curl_easy_setopt(p->curl, CURLOPT_READFUNCTION, lcurl_hpost_read_callback); + } + lua_settop(L, 1); return 1; } @@ -400,63 +406,12 @@ static int lcurl_easy_set_callback(lua_State *L, 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; - } + lcurl_set_callback(L, c, 2, method); - if(c->cb_ref != LUA_NOREF){ - luaL_unref(L, LCURL_LUA_REGISTRY, c->cb_ref); - c->cb_ref = LUA_NOREF; - } + curl_easy_setopt(p->curl, OPT_CB, (c->cb_ref == LUA_NOREF)?0:func); + curl_easy_setopt(p->curl, OPT_UD, (c->cb_ref == LUA_NOREF)?0:p); - 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); + return 1; } static int lcurl_write_callback_(lua_State*L, @@ -509,32 +464,32 @@ static int lcurl_easy_set_WRITEFUNCTION(lua_State *L){ //{ 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; - +static int lcurl_read_callback(lua_State *L, + lcurl_callback_t *rd, lcurl_read_buffer_t *rbuffer, + char *buffer, size_t size, size_t nitems +){ 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); + if(rbuffer->ref != LUA_NOREF){ + lua_rawgeti(L, LCURL_LUA_REGISTRY, rbuffer->ref); data = luaL_checklstring(L, -1, &data_size); lua_pop(L, 1); - data = data + p->rbuffer.off; - data_size -= p->rbuffer.off; + data = data + rbuffer->off; + data_size -= rbuffer->off; if(data_size > ret){ data_size = ret; memcpy(buffer, data, data_size); - p->rbuffer.off += data_size; + rbuffer->off += data_size; } else{ memcpy(buffer, data, data_size); - luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref); - p->rbuffer.ref = LUA_NOREF; + luaL_unref(L, LCURL_LUA_REGISTRY, rbuffer->ref); + rbuffer->ref = LUA_NOREF; } lua_settop(L, top); @@ -542,9 +497,9 @@ static int lcurl_read_callback(char *buffer, size_t size, size_t nitems, void *a } // buffer is clean - assert(p->rbuffer.ref == LUA_NOREF); + assert(rbuffer->ref == LUA_NOREF); - n = lcurl_util_push_cb(L, &p->rd); + n = lcurl_util_push_cb(L, rd); lua_pushnumber(L, ret); if(lua_pcall(L, n, LUA_MULTRET, 0)) return CURL_READFUNC_ABORT; @@ -557,8 +512,8 @@ static int lcurl_read_callback(char *buffer, size_t size, size_t nitems, void *a if(data_size > ret){ data_size = ret; - p->rbuffer.ref = luaL_ref(L, LCURL_LUA_REGISTRY); - p->rbuffer.off = data_size; + rbuffer->ref = luaL_ref(L, LCURL_LUA_REGISTRY); + rbuffer->off = data_size; } memcpy(buffer, data, data_size); @@ -566,6 +521,16 @@ static int lcurl_read_callback(char *buffer, size_t size, size_t nitems, void *a return data_size; } +static int lcurl_easy_read_callback(char *buffer, size_t size, size_t nitems, void *arg){ + lcurl_easy_t *p = arg; + return lcurl_read_callback(p->L, &p->rd, &p->rbuffer, buffer, size, nitems); +} + +static int lcurl_hpost_read_callback(char *buffer, size_t size, size_t nitems, void *arg){ + lcurl_hpost_stream_t *p = arg; + return lcurl_read_callback(p->L, &p->rd, &p->rbuffer, buffer, size, nitems); +} + 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, diff --git a/src/lceasy.h b/src/lceasy.h index 5d64928..a126b0f 100644 --- a/src/lceasy.h +++ b/src/lceasy.h @@ -22,11 +22,6 @@ enum { #undef LCURL_LNG_INDEX #undef OPT_ENTRY -typedef struct lcurl_read_buffer_tag{ - int ref; - int off; -}lcurl_read_buffer_t; - typedef struct lcurl_easy_tag{ lua_State *L; CURL *curl; diff --git a/src/lchttppost.c b/src/lchttppost.c index 376cf33..34d7492 100644 --- a/src/lchttppost.c +++ b/src/lchttppost.c @@ -13,6 +13,7 @@ int lcurl_hpost_create(lua_State *L, int error_mode){ p->post = p->last = 0; p->storage = lcurl_storage_init(L); p->err_mode = error_mode; + p->stream = 0; return 1; } @@ -153,6 +154,93 @@ static int lcurl_hpost_add_file(lua_State *L){ return 1; } +static lcurl_hpost_stream_t *lcurl_hpost_stream_add(lua_State *L, lcurl_hpost_t *p){ + lcurl_hpost_stream_t *ptr = p->stream; + lcurl_hpost_stream_t *stream = malloc(sizeof(lcurl_hpost_stream_t)); + if(!stream) return NULL; + + stream->L = L; + stream->rbuffer.ref = LUA_NOREF; + stream->rd.cb_ref = stream->rd.ud_ref = LUA_NOREF; + stream->next = NULL; + if(!p->stream) p->stream = stream; + else{ + while(ptr->next) ptr = ptr->next; + ptr->next = stream; + } + return stream; +} + +static void lcurl_hpost_stream_free(lua_State *L, lcurl_hpost_stream_t *ptr){ + if(ptr){ + luaL_unref(L, LCURL_LUA_REGISTRY, ptr->rbuffer.ref); + luaL_unref(L, LCURL_LUA_REGISTRY, ptr->rd.cb_ref); + luaL_unref(L, LCURL_LUA_REGISTRY, ptr->rd.ud_ref); + free(ptr); + } +} + +static void lcurl_hpost_stream_free_last(lua_State *L, lcurl_hpost_t *p){ + lcurl_hpost_stream_t *ptr = p->stream; + if(!ptr) return; + if(!ptr->next){ + lcurl_hpost_stream_free(L, ptr); + p->stream = 0; + } + + while(ptr->next->next) ptr = ptr->next; + lcurl_hpost_stream_free(L, ptr->next); + ptr->next = NULL; +} + +static void lcurl_hpost_stream_free_all(lua_State *L, lcurl_hpost_t *p){ + lcurl_hpost_stream_t *ptr = p->stream; + while(ptr){ + lcurl_hpost_stream_t *next = ptr->next; + lcurl_hpost_stream_free(L, ptr); + ptr = next; + } + p->stream = 0; +} + + +static int lcurl_hpost_add_stream(lua_State *L){ + // add_stream(name, length, writer [, context]) + lcurl_hpost_t *p = lcurl_gethpost(L); + size_t name_len; const char *name = luaL_checklstring(L, 2, &name_len); + size_t len = (size_t)luaL_checklong(L, 3); + CURLFORMcode code; + lcurl_callback_t rd = {LUA_NOREF, LUA_NOREF}; + lcurl_hpost_stream_t *stream; + + lcurl_set_callback(L, &rd, 4, "read"); + + luaL_argcheck(L, rd.cb_ref != LUA_NOREF, 4, "function expected"); + + stream = lcurl_hpost_stream_add(L, p); + if(!stream){ + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_FORM, CURL_FORMADD_MEMORY); + } + + stream->rd = rd; + + code = curl_formadd(&p->post, &p->last, + CURLFORM_PTRNAME, name, CURLFORM_NAMELENGTH, name_len, + CURLFORM_STREAM, stream, CURLFORM_CONTENTSLENGTH, len, + CURLFORM_END + ); + + if(code != CURL_FORMADD_OK){ + lcurl_hpost_stream_free_last(L, p); + return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_FORM, code); + } + + lcurl_storage_preserve_value(L, p->storage, 2); + + lua_settop(L, 1); + return 1; +} + static int lcurl_hpost_add_files(lua_State *L){ lcurl_hpost_t *p = lcurl_gethpost(L); size_t name_len; const char *name = luaL_checklstring(L, 2, &name_len); @@ -364,6 +452,8 @@ static int lcurl_hpost_free(lua_State *L){ p->storage = lcurl_storage_free(L, p->storage); } + lcurl_hpost_stream_free_all(L, p); + return 0; } @@ -373,6 +463,7 @@ static const struct luaL_Reg lcurl_hpost_methods[] = { {"add_content", lcurl_hpost_add_content }, {"add_buffer", lcurl_hpost_add_buffer }, {"add_file", lcurl_hpost_add_file }, + {"add_stream", lcurl_hpost_add_stream }, {"add_files", lcurl_hpost_add_files }, diff --git a/src/lchttppost.h b/src/lchttppost.h index 311ad35..6052ad1 100644 --- a/src/lchttppost.h +++ b/src/lchttppost.h @@ -2,13 +2,22 @@ #define _LCHTTPPOST_H_ #include "lcurl.h" +#include "lcutils.h" #include +typedef struct lcurl_hpost_stream_tag{ + lua_State *L; + lcurl_callback_t rd; + lcurl_read_buffer_t rbuffer; + struct lcurl_hpost_stream_tag *next; +}lcurl_hpost_stream_t; + typedef struct lcurl_hpost_tag{ struct curl_httppost *post; struct curl_httppost *last; int storage; int err_mode; + lcurl_hpost_stream_t *stream; }lcurl_hpost_t; int lcurl_hpost_create(lua_State *L, int error_mode); diff --git a/src/lcmulti.c b/src/lcmulti.c index 6171bc2..8b8a653 100644 --- a/src/lcmulti.c +++ b/src/lcmulti.c @@ -297,63 +297,12 @@ static int lcurl_multi_set_callback(lua_State *L, 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; - } + lcurl_set_callback(L, c, 2, method); - if(c->cb_ref != LUA_NOREF){ - luaL_unref(L, LCURL_LUA_REGISTRY, c->cb_ref); - c->cb_ref = LUA_NOREF; - } + curl_multi_setopt(p->curl, OPT_CB, (c->cb_ref == LUA_NOREF)?0:func); + curl_multi_setopt(p->curl, OPT_UD, (c->cb_ref == LUA_NOREF)?0:p); - 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_multi_setopt(p->curl, OPT_UD, p); - curl_multi_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_multi_setopt(p->curl, OPT_UD, 0); - curl_multi_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_multi_setopt(p->curl, OPT_UD, p); - curl_multi_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_multi_setopt(p->curl, OPT_UD, p); - curl_multi_setopt(p->curl, OPT_CB, func); - assert(1 == lua_gettop(L)); - return 1; - } - - lua_pushliteral(L, "invalid object type"); - return lua_error(L); + return 1; } //{Timer diff --git a/src/lcutils.c b/src/lcutils.c index cfeac76..0a758a8 100644 --- a/src/lcutils.c +++ b/src/lcutils.c @@ -136,6 +136,60 @@ void lcurl_util_set_const(lua_State *L, const lcurl_const_t *reg){ } } +int lcurl_set_callback(lua_State *L, lcurl_callback_t *c, int i, const char *method){ + int top = lua_gettop(L); + i = lua_absindex(L, i); + + luaL_argcheck(L, !lua_isnoneornil(L, i), i, "no function present"); + luaL_argcheck(L, (top < (i + 1)), i + 2, "no arguments expected"); + + // if(top > (i + 1)) lua_settop(L, i + 1); // this for force ignore other arguments + + assert((top == i)||(top == (i + 1))); + + 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) == (i + 1)){// function + context + c->ud_ref = luaL_ref(L, LCURL_LUA_REGISTRY); + c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY); + + assert(top == (2 + lua_gettop(L))); + return 1; + } + + assert(top == i); + + if(lua_isfunction(L, i)){ // function + c->cb_ref = luaL_ref(L, LCURL_LUA_REGISTRY); + + assert(top == (1 + lua_gettop(L))); + return 1; + } + + if(lua_isuserdata(L, i) || lua_istable(L, i)){ // object + lua_getfield(L, i, 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); + + assert(top == (1 + lua_gettop(L))); + return 1; + } + + lua_pushliteral(L, "invalid object type"); + return lua_error(L); +} + int lcurl_util_push_cb(lua_State *L, lcurl_callback_t *c){ assert(c->cb_ref != LUA_NOREF); lua_rawgeti(L, LCURL_LUA_REGISTRY, c->cb_ref); diff --git a/src/lcutils.h b/src/lcutils.h index 67c1c2e..727b94d 100644 --- a/src/lcutils.h +++ b/src/lcutils.h @@ -16,6 +16,11 @@ typedef struct lcurl_callback_tag{ int ud_ref; }lcurl_callback_t; +typedef struct lcurl_read_buffer_tag{ + int ref; + int off; +}lcurl_read_buffer_t; + int lcurl_storage_init(lua_State *L); void lcurl_storage_preserve_value(lua_State *L, int storage, int i); @@ -40,6 +45,8 @@ void lcurl_util_slist_to_table(lua_State *L, struct curl_slist* list); void lcurl_util_set_const(lua_State *L, const lcurl_const_t *reg); +int lcurl_set_callback(lua_State *L, lcurl_callback_t *c, int i, const char *method); + int lcurl_util_push_cb(lua_State *L, lcurl_callback_t *c); int lcurl_util_new_weak_table(lua_State*L, const char *mode);