static int plua_function_module_run(struct lua_State *L, char *file, struct event_function_args_t *args, struct varcont_t *v) { #if LUA_VERSION_NUM <= 502 lua_getfield(L, -1, "run"); if(lua_type(L, -1) != LUA_TFUNCTION) { #else if(lua_getfield(L, -1, "run") == 0) { #endif logprintf(LOG_ERR, "%s: run function missing", file); return 0; } int nrargs = 0; struct event_function_args_t *tmp1 = NULL; while(args) { tmp1 = args; nrargs++; switch(tmp1->var.type_) { case JSON_NUMBER: { char *tmp = NULL; int len = snprintf(NULL, 0, "%.*f", tmp1->var.decimals_, tmp1->var.number_); if((tmp = MALLOC(len+1)) == NULL) { OUT_OF_MEMORY /*LCOV_EXCL_LINE*/ } memset(tmp, 0, len+1); sprintf(tmp, "%.*f", tmp1->var.decimals_, tmp1->var.number_); lua_pushstring(L, tmp); FREE(tmp); } break; case JSON_STRING: lua_pushstring(L, tmp1->var.string_); FREE(tmp1->var.string_); break; case JSON_BOOL: lua_pushboolean(L, tmp1->var.bool_); break; } args = args->next; FREE(tmp1); } args = NULL; if(lua_pcall(L, nrargs, 1, 0) == LUA_ERRRUN) { if(lua_type(L, -1) == LUA_TNIL) { logprintf(LOG_ERR, "%s: syntax error", file); return 0; } if(lua_type(L, -1) == LUA_TSTRING) { logprintf(LOG_ERR, "%s", lua_tostring(L, -1)); lua_pop(L, 1); return 0; } } if(lua_isstring(L, -1) == 0 && lua_isnumber(L, -1) == 0 && lua_isboolean(L, -1) == 0) { logprintf(LOG_ERR, "%s: the run function returned %s, string, number or boolean expected", file, lua_typename(L, lua_type(L, -1))); return 0; } if(lua_isnumber(L, -1) == 1) { char *p = (char *)lua_tostring(L, -1); v->number_ = atof(p); v->decimals_ = nrDecimals(p); v->type_ = JSON_NUMBER; } else if(lua_isstring(L, -1) == 1) { int l = strlen(lua_tostring(L, -1)); if((v->string_ = REALLOC(v->string_, l+1)) == NULL) { OUT_OF_MEMORY } strcpy(v->string_, lua_tostring(L, -1)); v->type_ = JSON_STRING; v->free_ = 1; } else if(lua_isboolean(L, -1) == 1) {
static void tbl_basic_serialize(lua_State *L, serial_type *s, int type, int idx) { if (type == LUA_TBOOLEAN) { if (lua_toboolean(L, idx)) { writeTblFixed(s, "true", 4); } else { writeTblFixed(s, "false", 5); } } else if (type == LUA_TNUMBER) { lua_pushvalue(L, idx); size_t len; const char *n = lua_tolstring(L, -1, &len); writeTblFixed(s, n, len); lua_pop(L, 1); } else if (type == LUA_TSTRING) { size_t len; const char *str = lua_tolstring(L, idx, &len); writeTblFixed(s, "\"", 1); tbl_dump_string(s, str, len); writeTblFixed(s, "\"", 1); } else if (type == LUA_TFUNCTION) { writeTblFixed(s, "loadstring(\"", 12); lua_dump(L, tbl_dump_function, s); writeTblFixed(s, "\")", 2); } else if (type == LUA_TTABLE) { lua_pushstring(L, "__CLASSNAME"); lua_rawget(L, idx - 1); // This is an object, register for saving later if (!lua_isnil(L, -1)) { lua_pop(L, 1); writeTblFixed(s, "loadObject('", 12); writeTbl(s, get_name(L, s, idx)); writeTblFixed(s, "')", 2); add_process(L, s, idx); } // This is just a table, save it else { lua_pop(L, 1); int ktype, etype; writeTblFixed(s, "{", 1); /* table is in the stack at index 't' */ lua_pushnil(L); /* first key */ while (lua_next(L, idx - 1) != 0) { ktype = lua_type(L, -2); etype = lua_type(L, -1); // Only save allowed types if ( ((ktype == LUA_TBOOLEAN) || (ktype == LUA_TNUMBER) || (ktype == LUA_TSTRING) || (ktype == LUA_TFUNCTION) || (ktype == LUA_TTABLE)) && ((etype == LUA_TBOOLEAN) || (etype == LUA_TNUMBER) || (etype == LUA_TSTRING) || (etype == LUA_TFUNCTION) || (etype == LUA_TTABLE)) ) { writeTblFixed(s, "[", 1); tbl_basic_serialize(L, s, ktype, -2); writeTblFixed(s, "]=", 2); tbl_basic_serialize(L, s, etype, -1); writeTblFixed(s, ",\n", 2); } /* removes 'value'; keeps 'key' for next iteration */ lua_pop(L, 1); } writeTblFixed(s, "}\n", 2); } } else { printf("*WARNING* can not save value of type %s\n", lua_typename(L, type)); } }
static void mar_encode_value(lua_State *L, mar_Buffer *buf, int val, size_t *idx) { size_t l; int val_type = lua_type(L, val); if (lua_isinteger(L, val)) val_type = MAR_TINT; lua_pushvalue(L, val); buf_write(L, (const char*)&val_type, MAR_CHR, buf); switch (val_type) { case LUA_TBOOLEAN: { int int_val = lua_toboolean(L, -1); buf_write(L, (const char*)&int_val, MAR_CHR, buf); break; } case LUA_TSTRING: { const char *str_val = lua_tolstring(L, -1, &l); buf_write(L, (const char*)&l, MAR_I32, buf); buf_write(L, str_val, l, buf); break; } case LUA_TNUMBER: { lua_Number num_val = lua_tonumber(L, -1); buf_write(L, (const char*)&num_val, MAR_I64, buf); break; } case MAR_TINT: { lua_Integer num_val = lua_tointeger(L, -1); buf_write(L, (const char*)&num_val, MAR_I64, buf); break; } case LUA_TTABLE: { int tag, ref; lua_pushvalue(L, -1); lua_rawget(L, SEEN_IDX); if (!lua_isnil(L, -1)) { ref = lua_tointeger(L, -1); tag = MAR_TREF; buf_write(L, (const char*)&tag, MAR_CHR, buf); buf_write(L, (const char*)&ref, MAR_I32, buf); lua_pop(L, 1); } else { mar_Buffer rec_buf; lua_pop(L, 1); /* pop nil */ if (luaL_getmetafield(L, -1, "__persist")) { tag = MAR_TUSR; lua_pushvalue(L, -2); /* self */ lua_call(L, 1, 1); if (!lua_isfunction(L, -1)) { luaL_error(L, "__persist must return a function"); } lua_remove(L, -2); /* __persist */ lua_newtable(L); lua_pushvalue(L, -2); /* callback */ lua_rawseti(L, -2, 1); buf_init(L, &rec_buf); mar_encode_table(L, &rec_buf, idx); buf_write(L, (const char*)&tag, MAR_CHR, buf); buf_write(L, (const char*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); } else { tag = MAR_TVAL; lua_pushvalue(L, -1); lua_pushinteger(L, (*idx)++); lua_rawset(L, SEEN_IDX); lua_pushvalue(L, -1); buf_init(L, &rec_buf); mar_encode_table(L, &rec_buf, idx); lua_pop(L, 1); buf_write(L, (const char*)&tag, MAR_CHR, buf); buf_write(L, (const char*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data,rec_buf.head, buf); buf_done(L, &rec_buf); } } break; } case LUA_TFUNCTION: { int tag, ref; lua_pushvalue(L, -1); lua_rawget(L, SEEN_IDX); if (!lua_isnil(L, -1)) { ref = lua_tointeger(L, -1); tag = MAR_TREF; buf_write(L, (const char*)&tag, MAR_CHR, buf); buf_write(L, (const char*)&ref, MAR_I32, buf); lua_pop(L, 1); } else { mar_Buffer rec_buf; unsigned int i; lua_Debug ar; lua_pop(L, 1); /* pop nil */ lua_pushvalue(L, -1); lua_getinfo(L, ">nuS", &ar); if (ar.what[0] != 'L') { luaL_error(L, "attempt to persist a C function '%s'", ar.name); } tag = MAR_TVAL; lua_pushvalue(L, -1); lua_pushinteger(L, (*idx)++); lua_rawset(L, SEEN_IDX); lua_pushvalue(L, -1); buf_init(L, &rec_buf); lua_dump(L, (lua_Writer)buf_write, &rec_buf, true); buf_write(L, (const char*)&tag, MAR_CHR, buf); buf_write(L, (const char*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); lua_createtable(L, ar.nups, 0); for (i = 1; i <= ar.nups; i++) { const char* upvalue_name = lua_getupvalue(L, -2, i); if (strcmp("_ENV", upvalue_name) == 0) { lua_pop(L, 1); // Mark where _ENV is expected. lua_pushstring(L, MAR_ENV_IDX_KEY); lua_pushinteger(L, i); lua_rawset(L, -3); } else { lua_rawseti(L, -2, i); } } lua_pushstring(L, MAR_NUPS_IDX_KEY); lua_pushnumber(L, ar.nups); lua_rawset(L, -3); buf_init(L, &rec_buf); mar_encode_table(L, &rec_buf, idx); buf_write(L, (const char*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); lua_pop(L, 1); } break; } case LUA_TUSERDATA: { int tag, ref; lua_pushvalue(L, -1); lua_rawget(L, SEEN_IDX); if (!lua_isnil(L, -1)) { ref = lua_tointeger(L, -1); tag = MAR_TREF; buf_write(L, (const char*)&tag, MAR_CHR, buf); buf_write(L, (const char*)&ref, MAR_I32, buf); lua_pop(L, 1); } else { mar_Buffer rec_buf; lua_pop(L, 1); /* pop nil */ if (luaL_getmetafield(L, -1, "__persist")) { tag = MAR_TUSR; lua_pushvalue(L, -2); lua_pushinteger(L, (*idx)++); lua_rawset(L, SEEN_IDX); lua_pushvalue(L, -2); lua_call(L, 1, 1); if (!lua_isfunction(L, -1)) { luaL_error(L, "__persist must return a function"); } lua_newtable(L); lua_pushvalue(L, -2); lua_rawseti(L, -2, 1); lua_remove(L, -2); buf_init(L, &rec_buf); mar_encode_table(L, &rec_buf, idx); buf_write(L, (const char*)&tag, MAR_CHR, buf); buf_write(L, (const char*)&rec_buf.head, MAR_I32, buf); buf_write(L, rec_buf.data, rec_buf.head, buf); buf_done(L, &rec_buf); } else { luaL_error(L, "attempt to encode userdata (no __persist hook)"); } lua_pop(L, 1); } break; } case LUA_TNIL: break; default: luaL_error(L, "invalid value type (%s)", lua_typename(L, val_type)); } lua_pop(L, 1); }
/*** check whether the calling function's argument have the expected types. `checks( [level], t_1, ..., t_n)` causes an error if the type of argument #`i` in stack frame #`level` isn't as described by `t_i`, for i in `[1...n]`. `level` is optional, it defaults to one (checks the function immediately calling `checks`). @function [parent=#global] checks @param level the number of stack levels to ignore in the error message, should it be produced. Optional, defaults to 1. @param varargs one type string per expected argument. @return nothing on success, throw an error on failure. */ static int checks( lua_State *L) { lua_Debug ar; int level=1, i=1, r; if( lua_isnumber( L, 1)) { i = 2; level = lua_tointeger( L, 1); } r = lua_getstack( L, level, & ar); if( ! r) luaL_error( L, "checks() must be called within a Lua function"); /* loop for each checked argument in stack frame. */ for( /* i already initialized. */; ! lua_isnoneornil( L, i); i++) { const char *expectedType = luaL_checkstring( L, i); // - lua_getlocal( L, & ar, i); // val (value whose type is checked) /* 1. Check for nil if type is optional. */ if( '?' == expectedType[0]) { if( ! expectedType[1] /* expectedType == "?". */ || lua_isnoneornil( L, -1)) { /* actualType == "nil". */ lua_pop( L, 1); continue; // - } expectedType++; } const char *actualType = lua_typename( L, lua_type( L, -1)); /* 1'. if the template is "!", check for non-nilness. */ if( '!' == expectedType[0] && '\0' == expectedType[1]) { if( lua_isnoneornil( L, -1)) { // val==nil return error( L, level, i, "non-nil", actualType); } else { // val~=nil lua_pop( L, 1); continue; // - } } /* 2. Check real type. */ if( matches( actualType, expectedType)) { lua_pop( L, 1); continue; // - } /* 3. Check for type name in metatable. */ if( lua_getmetatable( L, -1)) { // val, mt lua_getfield( L, -1, "__type"); // val, mt, __type? if( lua_isstring( L, -1)) { // val, mt, __type if( matches( luaL_checkstring( L, -1), expectedType)) { lua_pop( L, 3); continue; // - } else { /* non-matching __type field. */ lua_pop( L, 2); // val } } else { /* no __type field. */ lua_pop( L, 2); // val } } else { /* no metatable. */ } // val /* 4. Check for a custom typechecking function. */ lua_getfield( L, LUA_REGISTRYINDEX, "checkers"); // val, checkers const char *p = expectedType; while( 1) { const char *q = strchr( p, '|'); if( ! q) q = p + strlen( p); lua_pushlstring( L, p, q-p); // val, checkers, expType lua_gettable( L, -2); // val, checkers, checkers.expType? if( lua_isfunction( L, -1)) { lua_pushvalue( L, -3); // val, checkers, checkers.expType, val r = lua_pcall( L, 1, 1, 0); // val, checkers, result || msg if( ! r && lua_toboolean( L, -1)) {// val, checkers, result==true lua_pop( L, 3); // - break; } else { // val, checkers, errormsg lua_pop( L, 1); // val, checkers } } else { /* no such custom checker */ // val, checkers, nil lua_pop( L, 1); // val, checkers } if( ! *q) { /* last possible expected type. */ lua_pop( L, 2); return error( L, level, i, expectedType, actualType); } else { p = q+1; } } /* for each expected type */ } /* for each i */ return 0; }
static int ngx_http_lua_ngx_re_sub_helper(lua_State *L, unsigned global) { ngx_http_lua_regex_t *re; ngx_http_request_t *r; ngx_str_t subj; ngx_str_t pat; ngx_str_t opts; ngx_str_t tpl; ngx_http_lua_main_conf_t *lmcf = NULL; ngx_pool_t *pool, *old_pool; ngx_lua_regex_compile_t re_comp; const char *msg; ngx_int_t rc; ngx_uint_t n; ngx_int_t i; int nargs; int *cap = NULL; int ovecsize; int type; unsigned func; int offset; size_t count; luaL_Buffer luabuf; ngx_int_t flags; u_char *p; u_char errstr[NGX_MAX_CONF_ERRSTR + 1]; pcre_extra *sd = NULL; ngx_http_lua_complex_value_t *ctpl = NULL; ngx_http_lua_compile_complex_value_t ccv; nargs = lua_gettop(L); if (nargs != 3 && nargs != 4) { return luaL_error(L, "expecting three or four arguments, but got %d", nargs); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "no request object found"); } subj.data = (u_char *) luaL_checklstring(L, 1, &subj.len); pat.data = (u_char *) luaL_checklstring(L, 2, &pat.len); func = 0; type = lua_type(L, 3); switch (type) { case LUA_TFUNCTION: func = 1; tpl.len = 0; tpl.data = (u_char *) ""; break; case LUA_TNUMBER: case LUA_TSTRING: tpl.data = (u_char *) lua_tolstring(L, 3, &tpl.len); break; default: msg = lua_pushfstring(L, "string, number, or function expected, " "got %s", lua_typename(L, type)); return luaL_argerror(L, 3, msg); } ngx_memzero(&re_comp, sizeof(ngx_lua_regex_compile_t)); if (nargs == 4) { opts.data = (u_char *) luaL_checklstring(L, 4, &opts.len); lua_pop(L, 1); } else { /* nargs == 3 */ opts.data = (u_char *) ""; opts.len = 0; } /* stack: subj regex repl */ re_comp.options = 0; flags = ngx_http_lua_ngx_re_parse_opts(L, &re_comp, &opts, 4); if (flags & NGX_LUA_RE_COMPILE_ONCE) { lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); pool = lmcf->pool; dd("server pool %p", lmcf->pool); lua_pushlightuserdata(L, &ngx_http_lua_regex_cache_key); lua_rawget(L, LUA_REGISTRYINDEX); /* table */ lua_pushliteral(L, "s"); lua_pushinteger(L, tpl.len); lua_pushliteral(L, ":"); lua_pushvalue(L, 2); if (tpl.len != 0) { lua_pushvalue(L, 3); } dd("options size: %d", (int) sizeof(re_comp.options)); lua_pushlstring(L, (char *) &re_comp.options, sizeof(re_comp.options)); /* table regex opts */ if (tpl.len == 0) { lua_concat(L, 5); /* table key */ } else { lua_concat(L, 6); /* table key */ } lua_pushvalue(L, -1); /* table key key */ dd("regex cache key: %.*s", (int) (pat.len + sizeof(re_comp.options)), lua_tostring(L, -1)); lua_rawget(L, -3); /* table key re */ re = lua_touserdata(L, -1); lua_pop(L, 1); /* table key */ if (re) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua regex cache hit for sub regex \"%s\" with options " "\"%s\" and replace \"%s\"", pat.data, opts.data, func ? (u_char *) "<func>" : tpl.data); lua_pop(L, 2); dd("restoring regex %p, ncaptures %d, captures %p", re->regex, re->ncaptures, re->captures); re_comp.regex = re->regex; sd = re->regex_sd; re_comp.captures = re->ncaptures; cap = re->captures; ctpl = re->replace; if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; } else { ovecsize = (re->ncaptures + 1) * 3; } goto exec; } ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua regex cache miss for %ssub regex \"%s\" with options " "\"%s\" and replace \"%s\"", global ? "g" : "", pat.data, opts.data, func ? (u_char *) "<func>" : tpl.data); if (lmcf->regex_cache_entries >= lmcf->regex_cache_max_entries) { if (lmcf->regex_cache_entries == lmcf->regex_cache_max_entries) { ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "lua exceeding regex cache max entries (%i)", lmcf->regex_cache_max_entries); lmcf->regex_cache_entries++; } pool = r->pool; flags &= ~NGX_LUA_RE_COMPILE_ONCE; } } else { pool = r->pool; } re_comp.pattern = pat; re_comp.err.len = NGX_MAX_CONF_ERRSTR; re_comp.err.data = errstr; re_comp.pool = pool; dd("compiling regex"); ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua compiling %ssub regex \"%s\" with options \"%s\" " "(compile once: %d) (dfa mode: %d) (jit mode: %d)", global ? "g" : "", pat.data, opts.data, (flags & NGX_LUA_RE_COMPILE_ONCE) != 0, (flags & NGX_LUA_RE_MODE_DFA) != 0, (flags & NGX_LUA_RE_MODE_JIT) != 0); old_pool = ngx_http_lua_pcre_malloc_init(pool); rc = ngx_lua_regex_compile(&re_comp); ngx_http_lua_pcre_malloc_done(old_pool); if (rc != NGX_OK) { dd("compile failed"); re_comp.err.data[re_comp.err.len] = '\0'; msg = lua_pushfstring(L, "failed to compile regex \"%s\": %s", pat.data, re_comp.err.data); return luaL_argerror(L, 2, msg); } #if LUA_HAVE_PCRE_JIT if (flags & NGX_LUA_RE_MODE_JIT) { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) dd("sd = %p", sd); if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", msg, sd); } if (sd != NULL) { int jitted; old_pool = ngx_http_lua_pcre_malloc_init(pool); pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted); ngx_http_lua_pcre_malloc_done(old_pool); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre JIT compiling result: %d", jitted); } # endif /* NGX_DEBUG */ } else { old_pool = ngx_http_lua_pcre_malloc_init(pool); sd = pcre_study(re_comp.regex, 0, &msg); ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) dd("sd = %p", sd); if (msg != NULL) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pcre_study failed with PCRE_STUDY_JIT_COMPILE: %s (%p)", msg, sd); } # endif /* NGX_DEBUG */ } #else /* LUA_HAVE_PCRE_JIT */ if (flags & NGX_LUA_RE_MODE_JIT) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "your pcre build does not have JIT support and " "the \"j\" regex option is ignored"); } #endif /* LUA_HAVE_PCRE_JIT */ dd("compile done, captures %d", re_comp.captures); if (flags & NGX_LUA_RE_MODE_DFA) { ovecsize = 2; } else { ovecsize = (re_comp.captures + 1) * 3; } cap = ngx_palloc(pool, ovecsize * sizeof(int)); if (cap == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; msg = "out of memory"; goto error; } if (func) { ctpl = NULL; } else { ctpl = ngx_palloc(pool, sizeof(ngx_http_lua_complex_value_t)); if (ctpl == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; msg = "out of memory"; goto error; } if ((flags & NGX_LUA_RE_COMPILE_ONCE) && tpl.len != 0) { /* copy the string buffer pointed to by tpl.data from Lua VM */ p = ngx_palloc(pool, tpl.len + 1); if (p == NULL) { flags &= ~NGX_LUA_RE_COMPILE_ONCE; msg = "out of memory"; goto error; } ngx_memcpy(p, tpl.data, tpl.len); p[tpl.len] = '\0'; tpl.data = p; } ngx_memzero(&ccv, sizeof(ngx_http_lua_compile_complex_value_t)); ccv.pool = pool; ccv.log = r->connection->log; ccv.value = &tpl; ccv.complex_value = ctpl; if (ngx_http_lua_compile_complex_value(&ccv) != NGX_OK) { ngx_pfree(pool, cap); ngx_pfree(pool, ctpl); if ((flags & NGX_LUA_RE_COMPILE_ONCE) && tpl.len != 0) { ngx_pfree(pool, tpl.data); } if (sd) { ngx_http_lua_regex_free_study_data(pool, sd); } ngx_pfree(pool, re_comp.regex); return luaL_error(L, "bad template for substitution: \"%s\"", lua_tostring(L, 3)); } } if (flags & NGX_LUA_RE_COMPILE_ONCE) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua saving compiled sub regex (%d captures) into the cache " "(entries %i)", re_comp.captures, lmcf ? lmcf->regex_cache_entries : 0); re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t)); if (re == NULL) { return luaL_error(L, "out of memory"); } dd("saving regex %p, ncaptures %d, captures %p", re_comp.regex, re_comp.captures, cap); re->regex = re_comp.regex; re->regex_sd = sd; re->ncaptures = re_comp.captures; re->captures = cap; re->replace = ctpl; lua_pushlightuserdata(L, re); /* table key value */ lua_rawset(L, -3); /* table */ lua_pop(L, 1); if (lmcf) { lmcf->regex_cache_entries++; } } exec: count = 0; offset = 0; for (;;) { if (subj.len == 0) { break; } if (flags & NGX_LUA_RE_MODE_DFA) { #if LUA_HAVE_PCRE_DFA int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT]; rc = ngx_http_lua_regex_dfa_exec(re_comp.regex, sd, &subj, offset, cap, ovecsize, ws, NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT); #else /* LUA_HAVE_PCRE_DFA */ msg = "at least pcre 6.0 is required for the DFA mode"; goto error; #endif /* LUA_HAVE_PCRE_DFA */ } else { rc = ngx_http_lua_regex_exec(re_comp.regex, sd, &subj, offset, cap, ovecsize); } if (rc == NGX_REGEX_NO_MATCHED) { break; } if (rc < 0) { msg = lua_pushfstring(L, ngx_regex_exec_n " failed: %d on \"%s\" " "using \"%s\"", (int) rc, subj.data, pat.data); goto error; } if (rc == 0) { if (flags & NGX_LUA_RE_MODE_DFA) { rc = 1; } else { msg = "capture size too small"; goto error; } } dd("rc = %d", (int) rc); count++; if (count == 1) { luaL_buffinit(L, &luabuf); } if (func) { lua_pushvalue(L, -1); lua_createtable(L, rc - 1 /* narr */, 1 /* nrec */); for (i = 0, n = 0; i < rc; i++, n += 2) { dd("capture %d: %d %d", (int) i, cap[n], cap[n + 1]); if (cap[n] < 0) { lua_pushnil(L); } else { lua_pushlstring(L, (char *) &subj.data[cap[n]], cap[n + 1] - cap[n]); dd("pushing capture %s at %d", lua_tostring(L, -1), (int) i); } lua_rawseti(L, -2, (int) i); } dd("stack size at call: %d", lua_gettop(L)); lua_call(L, 1 /* nargs */, 1 /* nresults */); type = lua_type(L, -1); switch (type) { case LUA_TNUMBER: case LUA_TSTRING: tpl.data = (u_char *) lua_tolstring(L, -1, &tpl.len); break; default: msg = lua_pushfstring(L, "string or number expected to be " "returned by the replace function, got %s", lua_typename(L, type)); return luaL_argerror(L, 3, msg); } luaL_addlstring(&luabuf, (char *) &subj.data[offset], cap[0] - offset); luaL_addlstring(&luabuf, (char *) tpl.data, tpl.len); lua_pop(L, 1); offset = cap[1]; if (global) { continue; } break; } rc = ngx_http_lua_complex_value(r, &subj, offset, rc, cap, ctpl, &luabuf); if (rc != NGX_OK) { msg = lua_pushfstring(L, "failed to eval the template for " "replacement: \"%s\"", tpl.data); goto error; } offset = cap[1]; if (global) { continue; } break; } if (count == 0) { dd("no match, just the original subject"); lua_settop(L, 1); } else { if (offset != (int) subj.len) { dd("adding trailer: %s (len %d)", &subj.data[offset], (int) (subj.len - offset)); luaL_addlstring(&luabuf, (char *) &subj.data[offset], subj.len - offset); } luaL_pushresult(&luabuf); dd("the dst string: %s", lua_tostring(L, -1)); } if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { if (sd) { ngx_http_lua_regex_free_study_data(pool, sd); } if (re_comp.regex) { ngx_pfree(pool, re_comp.regex); } if (ctpl) { ngx_pfree(pool, ctpl); } if (cap) { ngx_pfree(pool, cap); } } lua_pushinteger(L, count); return 2; error: if (!(flags & NGX_LUA_RE_COMPILE_ONCE)) { if (sd) { ngx_http_lua_regex_free_study_data(pool, sd); } if (re_comp.regex) { ngx_pfree(pool, re_comp.regex); } if (ctpl) { ngx_pfree(pool, ctpl); } if (cap) { ngx_pfree(pool, cap); } } return luaL_error(L, msg); }
static int luaB_type (lua_State *L) { int t = lua_type(L, 1); luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); lua_pushstring(L, lua_typename(L, t)); return 1; }
static int ngx_http_lua_ngx_location_capture_multi(lua_State *L) { ngx_http_request_t *r; ngx_http_request_t *sr = NULL; /* subrequest object */ ngx_http_post_subrequest_t *psr; ngx_http_lua_ctx_t *sr_ctx; ngx_http_lua_ctx_t *ctx; ngx_array_t *extra_vars; ngx_str_t uri; ngx_str_t args; ngx_str_t extra_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; size_t nargs; int rc; int n; int always_forward_body = 0; ngx_uint_t method; ngx_http_request_body_t *body; int type; ngx_buf_t *b; unsigned vars_action; ngx_uint_t nsubreqs; ngx_uint_t index; size_t sr_statuses_len; size_t sr_headers_len; size_t sr_bodies_len; size_t sr_flags_len; unsigned custom_ctx; ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_post_subrequest_data_t *psr_data; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "only one argument is expected, but got %d", n); } luaL_checktype(L, 1, LUA_TTABLE); nsubreqs = lua_objlen(L, 1); if (nsubreqs == 0) { return luaL_error(L, "at least one subrequest should be specified"); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); coctx = ctx->cur_co_ctx; if (coctx == NULL) { return luaL_error(L, "no co ctx found"); } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua location capture, uri:\"%V\" c:%ud", &r->uri, r->main->count); sr_statuses_len = nsubreqs * sizeof(ngx_int_t); sr_headers_len = nsubreqs * sizeof(ngx_http_headers_out_t *); sr_bodies_len = nsubreqs * sizeof(ngx_str_t); sr_flags_len = nsubreqs * sizeof(uint8_t); p = ngx_pcalloc(r->pool, sr_statuses_len + sr_headers_len + sr_bodies_len + sr_flags_len); if (p == NULL) { return luaL_error(L, "no memory"); } coctx->sr_statuses = (void *) p; p += sr_statuses_len; coctx->sr_headers = (void *) p; p += sr_headers_len; coctx->sr_bodies = (void *) p; p += sr_bodies_len; coctx->sr_flags = (void *) p; coctx->nsubreqs = nsubreqs; coctx->pending_subreqs = 0; extra_vars = NULL; for (index = 0; index < nsubreqs; index++) { coctx->pending_subreqs++; lua_rawgeti(L, 1, index + 1); if (lua_isnil(L, -1)) { return luaL_error(L, "only array-like tables are allowed"); } dd("queries query: top %d", lua_gettop(L)); if (lua_type(L, -1) != LUA_TTABLE) { return luaL_error(L, "the query argument %d is not a table, " "but a %s", index, lua_typename(L, lua_type(L, -1))); } nargs = lua_objlen(L, -1); if (nargs != 1 && nargs != 2) { return luaL_error(L, "query argument %d expecting one or " "two arguments", index); } lua_rawgeti(L, 2, 1); /* queries query uri */ dd("queries query uri: %d", lua_gettop(L)); dd("first arg in first query: %s", lua_typename(L, lua_type(L, -1))); body = NULL; ngx_str_null(&extra_args); if (extra_vars != NULL) { /* flush out existing elements in the array */ extra_vars->nelts = 0; } vars_action = 0; custom_ctx = 0; if (nargs == 2) { /* check out the options table */ lua_rawgeti(L, 2, 2); /* queries query uri opts */ dd("queries query uri opts: %d", lua_gettop(L)); if (lua_type(L, 4) != LUA_TTABLE) { return luaL_error(L, "expecting table as the 2nd argument for " "subrequest %d, but got %s", index, luaL_typename(L, 4)); } dd("queries query uri opts: %d", lua_gettop(L)); /* check the args option */ lua_getfield(L, 4, "args"); type = lua_type(L, -1); switch (type) { case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, -1, &extra_args); break; case LUA_TNIL: /* do nothing */ break; case LUA_TNUMBER: case LUA_TSTRING: extra_args.data = (u_char *) lua_tolstring(L, -1, &len); extra_args.len = len; break; default: return luaL_error(L, "Bad args option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the vars option */ lua_getfield(L, 4, "vars"); switch (lua_type(L, -1)) { case LUA_TTABLE: ngx_http_lua_process_vars_option(r, L, -1, &extra_vars); dd("post process vars top: %d", lua_gettop(L)); break; case LUA_TNIL: /* do nothing */ break; default: return luaL_error(L, "Bad vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the share_all_vars option */ lua_getfield(L, 4, "share_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_SHARE_ALL_VARS; } break; default: return luaL_error(L, "Bad share_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the copy_all_vars option */ lua_getfield(L, 4, "copy_all_vars"); switch (lua_type(L, -1)) { case LUA_TNIL: /* do nothing */ break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { vars_action |= NGX_HTTP_LUA_COPY_ALL_VARS; } break; default: return luaL_error(L, "Bad copy_all_vars option value"); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "forward_body" option */ lua_getfield(L, 4, "always_forward_body"); always_forward_body = lua_toboolean(L, -1); lua_pop(L, 1); dd("always foward body: %d", always_forward_body); /* check the "method" option */ lua_getfield(L, 4, "method"); type = lua_type(L, -1); if (type == LUA_TNIL) { method = NGX_HTTP_GET; } else { if (type != LUA_TNUMBER) { return luaL_error(L, "Bad http request method"); } method = (ngx_uint_t) lua_tonumber(L, -1); } lua_pop(L, 1); dd("queries query uri opts: %d", lua_gettop(L)); /* check the "ctx" option */ lua_getfield(L, 4, "ctx"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TTABLE) { return luaL_error(L, "Bad ctx option value type %s, " "expected a Lua table", lua_typename(L, type)); } custom_ctx = 1; } else { lua_pop(L, 1); } dd("queries query uri opts ctx?: %d", lua_gettop(L)); /* check the "body" option */ lua_getfield(L, 4, "body"); type = lua_type(L, -1); if (type != LUA_TNIL) { if (type != LUA_TSTRING && type != LUA_TNUMBER) { return luaL_error(L, "Bad http request body"); } body = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (body == NULL) { return luaL_error(L, "no memory"); } q = (u_char *) lua_tolstring(L, -1, &len); dd("request body: [%.*s]", (int) len, q); if (len) { b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { return luaL_error(L, "no memory"); } b->last = ngx_copy(b->last, q, len); body->bufs = ngx_alloc_chain_link(r->pool); if (body->bufs == NULL) { return luaL_error(L, "no memory"); } body->bufs->buf = b; body->bufs->next = NULL; body->buf = b; } } lua_pop(L, 1); /* pop the body */ /* stack: queries query uri opts ctx? */ lua_remove(L, 4); /* stack: queries query uri ctx? */ dd("queries query uri ctx?: %d", lua_gettop(L)); } else { method = NGX_HTTP_GET; } /* stack: queries query uri ctx? */ p = (u_char *) luaL_checklstring(L, 3, &len); uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "memory allocation error"); } ngx_memcpy(uri.data, p, len); uri.len = len; ngx_str_null(&args); flags = 0; rc = ngx_http_parse_unsafe_uri(r, &uri, &args, &flags); if (rc != NGX_OK) { dd("rc = %d", (int) rc); return luaL_error(L, "unsafe uri in argument #1: %s", p); } if (args.len == 0) { if (extra_args.len) { p = ngx_palloc(r->pool, extra_args.len); if (p == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(p, extra_args.data, extra_args.len); args.data = p; args.len = extra_args.len; } } else if (extra_args.len) { /* concatenate the two parts of args together */ len = args.len + (sizeof("&") - 1) + extra_args.len; p = ngx_palloc(r->pool, len); if (p == NULL) { return luaL_error(L, "no memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, extra_args.data, extra_args.len); args.data = p; args.len = len; } p = ngx_pnalloc(r->pool, sizeof(ngx_http_post_subrequest_t) + sizeof(ngx_http_lua_ctx_t) + sizeof(ngx_http_lua_post_subrequest_data_t)); if (p == NULL) { return luaL_error(L, "no memory"); } psr = (ngx_http_post_subrequest_t *) p; p += sizeof(ngx_http_post_subrequest_t); sr_ctx = (ngx_http_lua_ctx_t *) p; p += sizeof(ngx_http_lua_ctx_t); psr_data = (ngx_http_lua_post_subrequest_data_t *) p; ngx_memzero(sr_ctx, sizeof(ngx_http_lua_ctx_t)); /* set by ngx_memzero: * sr_ctx->run_post_subrequest = 0 * sr_ctx->free = NULL * sr_ctx->body = NULL */ psr_data->ctx = sr_ctx; psr_data->pr_co_ctx = coctx; psr->handler = ngx_http_lua_post_subrequest; psr->data = psr_data; rc = ngx_http_lua_subrequest(r, &uri, &args, &sr, psr, 0); if (rc != NGX_OK) { return luaL_error(L, "failed to issue subrequest: %d", (int) rc); } ngx_http_lua_init_ctx(sr, sr_ctx); sr_ctx->capture = 1; sr_ctx->index = index; sr_ctx->last_body = &sr_ctx->body; sr_ctx->vm_state = ctx->vm_state; ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module); rc = ngx_http_lua_adjust_subrequest(sr, method, always_forward_body, body, vars_action, extra_vars); if (rc != NGX_OK) { ngx_http_lua_cancel_subreq(sr); return luaL_error(L, "failed to adjust the subrequest: %d", (int) rc); } dd("queries query uri opts ctx? %d", lua_gettop(L)); /* stack: queries query uri ctx? */ if (custom_ctx) { ngx_http_lua_ngx_set_ctx_helper(L, sr, sr_ctx, -1); lua_pop(L, 3); } else { lua_pop(L, 2); } /* stack: queries */ } if (extra_vars) { ngx_array_destroy(extra_vars); } ctx->no_abort = 1; return lua_yield(L, 0); }
LUALIB_API int luaL_typerror (lua_State *L, int narg, const char *tname) { const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, lua_typename(L, lua_type(L,narg))); return luaL_argerror(L, narg, msg); }
static lsb_err_value encode_field_value(lsb_lua_sandbox *lsb, lsb_output_buffer *ob, int first, const char *representation, int value_type) { lsb_err_value ret = NULL; size_t len; const char *s; int t = lua_type(lsb->lua, -1); switch (t) { case LUA_TSTRING: switch (value_type) { case -1: // not specified defaults to string value_type = 0; case 0: case 1: break; default: snprintf(lsb->error_message, LSB_ERROR_SIZE, "invalid string value_type: %d", value_type); return LSB_ERR_HEKA_INPUT; } if (first) { // this uglyness keeps the protobuf fields in order without // additional lookups if (value_type == LSB_PB_BYTES) { ret = lsb_pb_write_key(ob, LSB_PB_VALUE_TYPE, LSB_PB_WT_VARINT); if (!ret) ret = lsb_pb_write_varint(ob, value_type); if (ret) return ret; } if (representation) { ret = lsb_pb_write_string(ob, LSB_PB_REPRESENTATION, representation, strlen(representation)); if (ret) return ret; } } s = lua_tolstring(lsb->lua, -1, &len); if (value_type == LSB_PB_BYTES) { ret = lsb_pb_write_string(ob, LSB_PB_VALUE_BYTES, s, len); if (ret) return ret; } else { ret = lsb_pb_write_string(ob, LSB_PB_VALUE_STRING, s, len); if (ret) return ret; } break; case LUA_TNUMBER: switch (value_type) { case -1: // not specified defaults to double value_type = 3; case 2: case 3: break; default: snprintf(lsb->error_message, LSB_ERROR_SIZE, "invalid numeric value_type: %d", value_type); return LSB_ERR_HEKA_INPUT; } if (first) { ret = lsb_pb_write_key(ob, LSB_PB_VALUE_TYPE, LSB_PB_WT_VARINT); if (!ret) ret = lsb_pb_write_varint(ob, value_type); if (ret) return ret; if (representation) { ret = lsb_pb_write_string(ob, LSB_PB_REPRESENTATION, representation, strlen(representation)); if (ret) return ret; } if (1 == first) { if (value_type == LSB_PB_INTEGER) { ret = lsb_pb_write_key(ob, LSB_PB_VALUE_INTEGER, LSB_PB_WT_VARINT); } else { ret = lsb_pb_write_key(ob, LSB_PB_VALUE_DOUBLE, LSB_PB_WT_FIXED64); } if (ret) return ret; } else { // pack array if (value_type == LSB_PB_INTEGER) { ret = lsb_pb_write_key(ob, LSB_PB_VALUE_INTEGER, LSB_PB_WT_LENGTH); if (!ret) ret = lsb_pb_write_varint(ob, 0); // length tbd later } else { ret = lsb_pb_write_key(ob, LSB_PB_VALUE_DOUBLE, LSB_PB_WT_LENGTH); if (!ret) ret = lsb_pb_write_varint(ob, first * sizeof(double)); } if (ret) return ret; } } if (value_type == LSB_PB_INTEGER) { ret = lsb_pb_write_varint(ob, lua_tointeger(lsb->lua, -1)); } else { ret = lsb_pb_write_double(ob, lua_tonumber(lsb->lua, -1)); } if (ret) return ret; break; case LUA_TBOOLEAN: if (value_type != -1 && value_type != LSB_PB_BOOL) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "invalid boolean value_type: %d", value_type); return LSB_ERR_HEKA_INPUT; } if (first) { ret = lsb_pb_write_key(ob, LSB_PB_VALUE_TYPE, LSB_PB_WT_VARINT); if (!ret) ret = lsb_pb_write_varint(ob, LSB_PB_BOOL); if (ret) return ret; if (representation) { ret = lsb_pb_write_string(ob, LSB_PB_REPRESENTATION, representation, strlen(representation)); if (ret) return ret; } if (1 == first) { ret = lsb_pb_write_key(ob, LSB_PB_VALUE_BOOL, LSB_PB_WT_VARINT); } else { ret = lsb_pb_write_key(ob, LSB_PB_VALUE_BOOL, LSB_PB_WT_LENGTH); if (!ret) ret = lsb_pb_write_varint(ob, first); } if (ret) return ret; } ret = lsb_pb_write_bool(ob, lua_toboolean(lsb->lua, -1)); break; case LUA_TTABLE: { lua_rawgeti(lsb->lua, -1, 1); int t = lua_type(lsb->lua, -1); lua_pop(lsb->lua, 1); // remove the array test value switch (t) { case LUA_TNIL: ret = encode_field_object(lsb, ob); break; case LUA_TNUMBER: case LUA_TSTRING: case LUA_TBOOLEAN: ret = encode_field_array(lsb, ob, t, representation, value_type); break; default: snprintf(lsb->error_message, LSB_ERROR_SIZE, "unsupported array type: %s", lua_typename(lsb->lua, t)); return LSB_ERR_LUA; } } break; case LUA_TLIGHTUSERDATA: lua_getfield(lsb->lua, -4, "userdata"); if (lua_type(lsb->lua, -1) != LUA_TUSERDATA) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "a lightuserdata output must also specify a userdata value"); return LSB_ERR_LUA; } // fall thru case LUA_TUSERDATA: { lua_CFunction fp = lsb_get_output_function(lsb->lua, -1); size_t len_pos = 0; if (!fp) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "userdata object does not implement lsb_output"); return LSB_ERR_LUA; } if (first) { ret = lsb_pb_write_key(ob, LSB_PB_VALUE_TYPE, LSB_PB_WT_VARINT); if (ret) return ret; // encode userdata as a byte array ret = lsb_pb_write_varint(ob, LSB_PB_BYTES); if (ret) return ret; if (representation) { ret = lsb_pb_write_string(ob, LSB_PB_REPRESENTATION, representation, strlen(representation)); if (ret) return ret; } } ret = lsb_pb_write_key(ob, LSB_PB_VALUE_BYTES, LSB_PB_WT_LENGTH); if (ret) return ret; len_pos = ob->pos; ret = lsb_pb_write_varint(ob, 0); // length tbd later if (ret) return ret; lua_pushlightuserdata(lsb->lua, ob); int result = fp(lsb->lua); lua_pop(lsb->lua, 1); // remove output function if (result) { snprintf(lsb->error_message, LSB_ERROR_SIZE, "userdata output callback failed: %d", result); return LSB_ERR_LUA; } ret = lsb_pb_update_field_length(ob, len_pos); } if (t == LUA_TLIGHTUSERDATA) lua_pop(lsb->lua, 1); // remove the userdata break; default: snprintf(lsb->error_message, LSB_ERROR_SIZE, "unsupported type: %s", lua_typename(lsb->lua, t)); return LSB_ERR_LUA; } return ret; }
static void value_error(lua_State *L, const char *name) { luaL_error(L, "invalid value of attribute `%s' (%s)", name, lua_typename(L, lua_type(L, -1))); }
static int ngx_http_lua_socket_udp_send(lua_State *L) { ssize_t n; ngx_http_request_t *r; u_char *p; size_t len; ngx_http_lua_socket_udp_upstream_t *u; int type; const char *msg; ngx_str_t query; ngx_http_lua_loc_conf_t *llcf; if (lua_gettop(L) != 2) { return luaL_error(L, "expecting 2 arguments (including the object), " "but got %d", lua_gettop(L)); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); if (r == NULL) { return luaL_error(L, "request object not found"); } luaL_checktype(L, 1, LUA_TTABLE); lua_rawgeti(L, 1, SOCKET_CTX_INDEX); u = lua_touserdata(L, -1); lua_pop(L, 1); if (u == NULL || u->udp_connection.connection == NULL) { llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_socket_errors) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to send data on a closed socket: u:%p, c:%p", u, u ? u->udp_connection.connection : NULL); } lua_pushnil(L); lua_pushliteral(L, "closed"); return 2; } if (u->ft_type) { u->ft_type = 0; } if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); return 2; } type = lua_type(L, 2); switch (type) { case LUA_TNUMBER: case LUA_TSTRING: lua_tolstring(L, 2, &len); break; case LUA_TTABLE: len = ngx_http_lua_calc_strlen_in_table(L, 2, 2, 1 /* strict */); break; default: msg = lua_pushfstring(L, "string, number, boolean, nil, " "or array table expected, got %s", lua_typename(L, type)); return luaL_argerror(L, 2, msg); } query.data = lua_newuserdata(L, len); query.len = len; switch (type) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) lua_tolstring(L, 2, &len); ngx_memcpy(query.data, (u_char *) p, len); break; case LUA_TTABLE: (void) ngx_http_lua_copy_str_in_table(L, 2, query.data); break; default: return luaL_error(L, "impossible to reach here"); } u->ft_type = 0; /* mimic ngx_http_upstream_init_request here */ #if 1 u->waiting = 0; #endif dd("sending query %.*s", (int) query.len, query.data); n = ngx_send(u->udp_connection.connection, query.data, query.len); dd("ngx_send returns %d (query len %d)", (int) n, (int) query.len); if (n == NGX_ERROR || n == NGX_AGAIN) { u->socket_errno = ngx_socket_errno; return ngx_http_lua_socket_error_retval_handler(r, u, L); } if (n != (ssize_t) query.len) { dd("not the while query was sent"); u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_PARTIALWRITE; return ngx_http_lua_socket_error_retval_handler(r, u, L); } dd("n == len"); lua_pushinteger(L, 1); return 1; }
static int ngx_http_lua_parse_args(ngx_http_request_t *r, lua_State *L, u_char *buf, u_char *last) { u_char *p, *q; u_char *src, *dst; unsigned parsing_value; size_t len; p = buf; parsing_value = 0; q = p; while (p != last) { if (*p == '=' && ! parsing_value) { /* key data is between p and q */ src = q; dst = q; ngx_http_lua_unescape_uri(&dst, &src, p - q, NGX_UNESCAPE_URI_COMPONENT); dd("pushing key %.*s", (int) (dst - q), q); /* push the key */ lua_pushlstring(L, (char *) q, dst - q); /* skip the current '=' char */ p++; q = p; parsing_value = 1; } else if (*p == '&') { /* reached the end of a key or a value, just save it */ src = q; dst = q; ngx_http_lua_unescape_uri(&dst, &src, p - q, NGX_UNESCAPE_URI_COMPONENT); dd("pushing key or value %.*s", (int) (dst - q), q); /* push the value or key */ lua_pushlstring(L, (char *) q, dst - q); /* skip the current '&' char */ p++; q = p; if (parsing_value) { /* end of the current pair's value */ parsing_value = 0; } else { /* the current parsing pair takes no value, * just push the value "true" */ dd("pushing boolean true"); lua_pushboolean(L, 1); } (void) lua_tolstring(L, -2, &len); if (len == 0) { /* ignore empty string key pairs */ dd("popping key and value..."); lua_pop(L, 2); } else { dd("setting table..."); ngx_http_lua_set_multi_value_table(L, 1); } } else { p++; } } if (p != q || parsing_value) { src = q; dst = q; ngx_http_lua_unescape_uri(&dst, &src, p - q, NGX_UNESCAPE_URI_COMPONENT); dd("pushing key or value %.*s", (int) (dst - q), q); lua_pushlstring(L, (char *) q, dst - q); if (! parsing_value) { dd("pushing boolean true..."); lua_pushboolean(L, 1); } (void) lua_tolstring(L, -2, &len); if (len == 0) { /* ignore empty string key pairs */ dd("popping key and value..."); lua_pop(L, 2); } else { dd("setting table..."); ngx_http_lua_set_multi_value_table(L, 1); } } dd("gettop: %d", lua_gettop(L)); dd("type: %s", lua_typename(L, lua_type(L, 1))); if (lua_gettop(L) != 1) { return luaL_error(L, "internal error: stack in bad state"); } return 1; }
static int luaB_type (lua_State *L) { luaL_checkany(L, 1); lua_pushstring(L, lua_typename(L, lua_type(L, 1))); return 1; }
int luaT_checkboolean(lua_State *L, int narg) { if(!lua_isboolean(L, narg)) luaT_typerror(L, narg, lua_typename(L, LUA_TBOOLEAN)); return lua_toboolean(L, narg); }
AString cLuaState::GetTypeText(int a_StackPos) { return lua_typename(m_LuaState, lua_type(m_LuaState, a_StackPos)); }
static void tag_error (lua_State *L, int arg, int tag) { typeerror(L, arg, lua_typename(L, tag)); }
int cLuaState::CopyStackFrom(cLuaState & a_SrcLuaState, int a_SrcStart, int a_SrcEnd) { /* // DEBUG: LOGD("Copying stack values from %d to %d", a_SrcStart, a_SrcEnd); a_SrcLuaState.LogStack("Src stack before copying:"); LogStack("Dst stack before copying:"); */ for (int i = a_SrcStart; i <= a_SrcEnd; ++i) { int t = lua_type(a_SrcLuaState, i); switch (t) { case LUA_TNIL: { lua_pushnil(m_LuaState); break; } case LUA_TSTRING: { AString s; a_SrcLuaState.ToString(i, s); Push(s); break; } case LUA_TBOOLEAN: { bool b = (tolua_toboolean(a_SrcLuaState, i, false) != 0); Push(b); break; } case LUA_TNUMBER: { lua_Number d = tolua_tonumber(a_SrcLuaState, i, 0); Push(d); break; } case LUA_TUSERDATA: { // Get the class name: const char * type = nullptr; if (lua_getmetatable(a_SrcLuaState, i) == 0) { LOGWARNING("%s: Unknown class in pos %d, cannot copy.", __FUNCTION__, i); lua_pop(m_LuaState, i - a_SrcStart); return -1; } lua_rawget(a_SrcLuaState, LUA_REGISTRYINDEX); // Stack +1 type = lua_tostring(a_SrcLuaState, -1); lua_pop(a_SrcLuaState, 1); // Stack -1 // Copy the value: void * ud = tolua_touserdata(a_SrcLuaState, i, nullptr); tolua_pushusertype(m_LuaState, ud, type); break; } default: { LOGWARNING("%s: Unsupported value: '%s' at stack position %d. Can only copy numbers, strings, bools and classes!", __FUNCTION__, lua_typename(a_SrcLuaState, t), i ); a_SrcLuaState.LogStack("Stack where copying failed:"); lua_pop(m_LuaState, i - a_SrcStart); return -1; } } } return a_SrcEnd - a_SrcStart + 1; }
static void tag_error (lua_State *L, int narg, int tag) { luaL_typerror(L, narg, lua_typename(L, tag)); }
int MyCPrint( lua_State* L ) { // 获取参数数量 int nArgs = lua_gettop(L); for (int i = 1; i <= nArgs; i++) { // 获取参数类型 size_t nLen = 0; int bRet = 0; LUA_INTEGER nRet = 0; LUA_NUMBER dblRet = 0; const void* pAddr = NULL; const char* szRet = NULL; lua_State* pL = NULL; lua_CFunction pFunc = 0; int nType = lua_type(L, i); switch (nType) { case LUA_TNIL: printf("参数 %d 类型为:NIL\n", i); break; case LUA_TBOOLEAN: bRet = lua_toboolean(L, i); printf("参数 %d 类型为:BOOLEAN value = %s\n", i, (!!bRet ? "true" : "false")); break; case LUA_TLIGHTUSERDATA: pAddr = lua_touserdata(L, i); printf("参数 %d 类型为:LIGHTUSERDATA pointer = 0x%08X\n", i, (int)pAddr); break; case LUA_TNUMBER: nRet = lua_tointeger(L, i); dblRet = lua_tonumber(L, i); if (nRet < dblRet) // 浮点数 { printf("参数 %d 类型为:NUMBER value = %g\n", i, dblRet); } else { printf("参数 %d 类型为:NUMBER value = %ld\n", i, nRet); } break; case LUA_TSTRING: nLen = lua_objlen(L, i); szRet = lua_tostring(L, i); printf("参数 %d 类型为:STRING len = %u value = %s\n", i, nLen, szRet); break; case LUA_TTABLE: nLen = lua_objlen(L, i); pAddr = lua_topointer(L, i); printf("参数 %d 类型为:TABLE len = %u pointer = 0x%p\n", i, nLen, (int)pAddr); break; case LUA_TFUNCTION: nLen = lua_objlen(L, i); pFunc = lua_tocfunction(L, i); printf("参数 %d 类型为:FUNCTION len = %u pointer = 0x%p\n", i, nLen, (int)pFunc); break; case LUA_TUSERDATA: pAddr = lua_touserdata(L, i); printf("参数 %d 类型为:USERDATA pointer = 0x%p\n", i, (int)pAddr); break; case LUA_TTHREAD: pL = lua_tothread(L, i); printf("参数 %d 类型为:THREAD pointer = 0x%p\n", i, (int)pL); break; default: nLen = lua_objlen(L, i); szRet = lua_typename(L, i); printf("参数 %d 类型未知!len = %u typename = %s\n", i, nLen, szRet); break; } } return 0; }