Add. form:add_stream() method. (See #1)

This commit is contained in:
Alexey Melnichuk 2014-09-02 14:13:11 +05:00
parent 1acb9b9de1
commit fcae9eabc8
7 changed files with 200 additions and 130 deletions

View File

@ -277,6 +277,8 @@ static int lcurl_easy_set_POSTFIELDS(lua_State *L){
#undef LCURL_LST_OPT #undef LCURL_LST_OPT
#undef LCURL_LNG_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){ static int lcurl_easy_set_HTTPPOST(lua_State *L){
lcurl_easy_t *p = lcurl_geteasy(L); lcurl_easy_t *p = lcurl_geteasy(L);
lcurl_hpost_t *post = lcurl_gethpost_at(L, 2); 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); 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); lua_settop(L, 1);
return 1; return 1;
} }
@ -400,63 +406,12 @@ static int lcurl_easy_set_callback(lua_State *L,
const char *method, void *func const char *method, void *func
) )
{ {
if(c->ud_ref != LUA_NOREF){ lcurl_set_callback(L, c, 2, method);
luaL_unref(L, LCURL_LUA_REGISTRY, c->ud_ref);
c->ud_ref = LUA_NOREF;
}
if(c->cb_ref != LUA_NOREF){ curl_easy_setopt(p->curl, OPT_CB, (c->cb_ref == LUA_NOREF)?0:func);
luaL_unref(L, LCURL_LUA_REGISTRY, c->cb_ref); curl_easy_setopt(p->curl, OPT_UD, (c->cb_ref == LUA_NOREF)?0:p);
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; 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, static int lcurl_write_callback_(lua_State*L,
@ -509,32 +464,32 @@ static int lcurl_easy_set_WRITEFUNCTION(lua_State *L){
//{ Reader //{ Reader
static int lcurl_read_callback(char *buffer, size_t size, size_t nitems, void *arg){ static int lcurl_read_callback(lua_State *L,
lcurl_easy_t *p = arg; lcurl_callback_t *rd, lcurl_read_buffer_t *rbuffer,
lua_State *L = p->L; char *buffer, size_t size, size_t nitems
){
const char *data; size_t data_size; const char *data; size_t data_size;
size_t ret = size * nitems; size_t ret = size * nitems;
int n, top = lua_gettop(L); int n, top = lua_gettop(L);
if(p->rbuffer.ref != LUA_NOREF){ if(rbuffer->ref != LUA_NOREF){
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->rbuffer.ref); lua_rawgeti(L, LCURL_LUA_REGISTRY, rbuffer->ref);
data = luaL_checklstring(L, -1, &data_size); data = luaL_checklstring(L, -1, &data_size);
lua_pop(L, 1); lua_pop(L, 1);
data = data + p->rbuffer.off; data = data + rbuffer->off;
data_size -= p->rbuffer.off; data_size -= rbuffer->off;
if(data_size > ret){ if(data_size > ret){
data_size = ret; data_size = ret;
memcpy(buffer, data, data_size); memcpy(buffer, data, data_size);
p->rbuffer.off += data_size; rbuffer->off += data_size;
} }
else{ else{
memcpy(buffer, data, data_size); memcpy(buffer, data, data_size);
luaL_unref(L, LCURL_LUA_REGISTRY, p->rbuffer.ref); luaL_unref(L, LCURL_LUA_REGISTRY, rbuffer->ref);
p->rbuffer.ref = LUA_NOREF; rbuffer->ref = LUA_NOREF;
} }
lua_settop(L, top); 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 // 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); lua_pushnumber(L, ret);
if(lua_pcall(L, n, LUA_MULTRET, 0)) return CURL_READFUNC_ABORT; 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){ if(data_size > ret){
data_size = ret; data_size = ret;
p->rbuffer.ref = luaL_ref(L, LCURL_LUA_REGISTRY); rbuffer->ref = luaL_ref(L, LCURL_LUA_REGISTRY);
p->rbuffer.off = data_size; rbuffer->off = data_size;
} }
memcpy(buffer, data, 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; 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){ static int lcurl_easy_set_READFUNCTION(lua_State *L){
lcurl_easy_t *p = lcurl_geteasy(L); lcurl_easy_t *p = lcurl_geteasy(L);
return lcurl_easy_set_callback(L, p, &p->rd, return lcurl_easy_set_callback(L, p, &p->rd,

View File

@ -22,11 +22,6 @@ enum {
#undef LCURL_LNG_INDEX #undef LCURL_LNG_INDEX
#undef OPT_ENTRY #undef OPT_ENTRY
typedef struct lcurl_read_buffer_tag{
int ref;
int off;
}lcurl_read_buffer_t;
typedef struct lcurl_easy_tag{ typedef struct lcurl_easy_tag{
lua_State *L; lua_State *L;
CURL *curl; CURL *curl;

View File

@ -13,6 +13,7 @@ int lcurl_hpost_create(lua_State *L, int error_mode){
p->post = p->last = 0; p->post = p->last = 0;
p->storage = lcurl_storage_init(L); p->storage = lcurl_storage_init(L);
p->err_mode = error_mode; p->err_mode = error_mode;
p->stream = 0;
return 1; return 1;
} }
@ -153,6 +154,93 @@ static int lcurl_hpost_add_file(lua_State *L){
return 1; 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){ static int lcurl_hpost_add_files(lua_State *L){
lcurl_hpost_t *p = lcurl_gethpost(L); lcurl_hpost_t *p = lcurl_gethpost(L);
size_t name_len; const char *name = luaL_checklstring(L, 2, &name_len); 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); p->storage = lcurl_storage_free(L, p->storage);
} }
lcurl_hpost_stream_free_all(L, p);
return 0; return 0;
} }
@ -373,6 +463,7 @@ static const struct luaL_Reg lcurl_hpost_methods[] = {
{"add_content", lcurl_hpost_add_content }, {"add_content", lcurl_hpost_add_content },
{"add_buffer", lcurl_hpost_add_buffer }, {"add_buffer", lcurl_hpost_add_buffer },
{"add_file", lcurl_hpost_add_file }, {"add_file", lcurl_hpost_add_file },
{"add_stream", lcurl_hpost_add_stream },
{"add_files", lcurl_hpost_add_files }, {"add_files", lcurl_hpost_add_files },

View File

@ -2,13 +2,22 @@
#define _LCHTTPPOST_H_ #define _LCHTTPPOST_H_
#include "lcurl.h" #include "lcurl.h"
#include "lcutils.h"
#include <stdlib.h> #include <stdlib.h>
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{ typedef struct lcurl_hpost_tag{
struct curl_httppost *post; struct curl_httppost *post;
struct curl_httppost *last; struct curl_httppost *last;
int storage; int storage;
int err_mode; int err_mode;
lcurl_hpost_stream_t *stream;
}lcurl_hpost_t; }lcurl_hpost_t;
int lcurl_hpost_create(lua_State *L, int error_mode); int lcurl_hpost_create(lua_State *L, int error_mode);

View File

@ -297,63 +297,12 @@ static int lcurl_multi_set_callback(lua_State *L,
const char *method, void *func const char *method, void *func
) )
{ {
if(c->ud_ref != LUA_NOREF){ lcurl_set_callback(L, c, 2, method);
luaL_unref(L, LCURL_LUA_REGISTRY, c->ud_ref);
c->ud_ref = LUA_NOREF;
}
if(c->cb_ref != LUA_NOREF){ curl_multi_setopt(p->curl, OPT_CB, (c->cb_ref == LUA_NOREF)?0:func);
luaL_unref(L, LCURL_LUA_REGISTRY, c->cb_ref); curl_multi_setopt(p->curl, OPT_UD, (c->cb_ref == LUA_NOREF)?0:p);
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_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; 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);
} }
//{Timer //{Timer

View File

@ -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){ int lcurl_util_push_cb(lua_State *L, lcurl_callback_t *c){
assert(c->cb_ref != LUA_NOREF); assert(c->cb_ref != LUA_NOREF);
lua_rawgeti(L, LCURL_LUA_REGISTRY, c->cb_ref); lua_rawgeti(L, LCURL_LUA_REGISTRY, c->cb_ref);

View File

@ -16,6 +16,11 @@ typedef struct lcurl_callback_tag{
int ud_ref; int ud_ref;
}lcurl_callback_t; }lcurl_callback_t;
typedef struct lcurl_read_buffer_tag{
int ref;
int off;
}lcurl_read_buffer_t;
int lcurl_storage_init(lua_State *L); int lcurl_storage_init(lua_State *L);
void lcurl_storage_preserve_value(lua_State *L, int storage, int i); 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); 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_push_cb(lua_State *L, lcurl_callback_t *c);
int lcurl_util_new_weak_table(lua_State*L, const char *mode); int lcurl_util_new_weak_table(lua_State*L, const char *mode);