u_char * ngx_stream_lua_copy_str_in_table(lua_State *L, int index, u_char *dst) { double key; int max; int i; int type; size_t len; u_char *p; if (index < 0) { index = lua_gettop(L) + index + 1; } max = 0; lua_pushnil(L); /* stack: table key */ while (lua_next(L, index) != 0) { /* stack: table key value */ key = lua_tonumber(L, -2); if (key > max) { max = (int) key; } lua_pop(L, 1); /* stack: table key */ } for (i = 1; i <= max; i++) { lua_rawgeti(L, index, i); /* stack: table value */ type = lua_type(L, -1); switch (type) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) lua_tolstring(L, -1, &len); dst = ngx_copy(dst, p, len); break; case LUA_TNIL: *dst++ = 'n'; *dst++ = 'i'; *dst++ = 'l'; break; case LUA_TBOOLEAN: if (lua_toboolean(L, -1)) { *dst++ = 't'; *dst++ = 'r'; *dst++ = 'u'; *dst++ = 'e'; } else { *dst++ = 'f'; *dst++ = 'a'; *dst++ = 'l'; *dst++ = 's'; *dst++ = 'e'; } break; case LUA_TTABLE: dst = ngx_stream_lua_copy_str_in_table(L, -1, dst); break; case LUA_TLIGHTUSERDATA: *dst++ = 'n'; *dst++ = 'u'; *dst++ = 'l'; *dst++ = 'l'; break; default: luaL_error(L, "impossible to reach here"); return NULL; } lua_pop(L, 1); /* stack: table */ } return dst; }
static int ngx_stream_lua_ngx_echo(lua_State *L, unsigned newline) { ngx_stream_session_t *s; ngx_stream_lua_ctx_t *ctx; const char *p; size_t len; size_t size; ngx_buf_t *b; ngx_chain_t *cl; ngx_int_t rc; int i; int nargs; int type; const char *msg; s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "no session object found"); } ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module); if (ctx == NULL) { return luaL_error(L, "no session ctx found"); } ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT); if (ctx->acquired_raw_req_socket) { lua_pushnil(L); lua_pushliteral(L, "raw session socket acquired"); return 2; } if (ctx->eof) { lua_pushnil(L); lua_pushliteral(L, "seen eof"); return 2; } nargs = lua_gettop(L); size = 0; for (i = 1; i <= nargs; i++) { type = lua_type(L, i); switch (type) { case LUA_TNUMBER: case LUA_TSTRING: lua_tolstring(L, i, &len); size += len; break; case LUA_TNIL: size += sizeof("nil") - 1; break; case LUA_TBOOLEAN: if (lua_toboolean(L, i)) { size += sizeof("true") - 1; } else { size += sizeof("false") - 1; } break; case LUA_TTABLE: size += ngx_stream_lua_calc_strlen_in_table(L, i, i, 0 /* strict */); break; case LUA_TLIGHTUSERDATA: dd("userdata: %p", lua_touserdata(L, i)); if (lua_touserdata(L, i) == NULL) { size += sizeof("null") - 1; break; } continue; default: msg = lua_pushfstring(L, "string, number, boolean, nil, " "ngx.null, or array table expected, " "but got %s", lua_typename(L, type)); return luaL_argerror(L, i, msg); } } if (newline) { size += sizeof("\n") - 1; } if (size == 0) { /* do nothing for empty strings */ lua_pushinteger(L, 1); return 1; } cl = ngx_stream_lua_chain_get_free_buf(s->connection->log, s->connection->pool, &ctx->free_bufs, size); if (cl == NULL) { return luaL_error(L, "no memory"); } b = cl->buf; for (i = 1; i <= nargs; i++) { type = lua_type(L, i); switch (type) { case LUA_TNUMBER: case LUA_TSTRING: p = lua_tolstring(L, i, &len); b->last = ngx_copy(b->last, (u_char *) p, len); break; case LUA_TNIL: *b->last++ = 'n'; *b->last++ = 'i'; *b->last++ = 'l'; break; case LUA_TBOOLEAN: if (lua_toboolean(L, i)) { *b->last++ = 't'; *b->last++ = 'r'; *b->last++ = 'u'; *b->last++ = 'e'; } else { *b->last++ = 'f'; *b->last++ = 'a'; *b->last++ = 'l'; *b->last++ = 's'; *b->last++ = 'e'; } break; case LUA_TTABLE: b->last = ngx_stream_lua_copy_str_in_table(L, i, b->last); break; case LUA_TLIGHTUSERDATA: *b->last++ = 'n'; *b->last++ = 'u'; *b->last++ = 'l'; *b->last++ = 'l'; break; default: return luaL_error(L, "impossible to reach here"); } } if (newline) { *b->last++ = '\n'; } #if 0 if (b->last != b->end) { return luaL_error(L, "buffer error: %p != %p", b->last, b->end); } #endif ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, newline ? "stream lua say response" : "stream lua print response"); rc = ngx_stream_lua_send_chain_link(s, ctx, cl); if (rc == NGX_ERROR) { lua_pushnil(L); lua_pushliteral(L, "nginx output filter error"); return 2; } dd("downstream write: %d, buf len: %d", (int) rc, (int) (b->last - b->pos)); lua_pushinteger(L, 1); return 1; }
static int ngx_stream_lua_socket_udp_send(lua_State *L) { ssize_t n; ngx_stream_session_t *s; u_char *p; size_t len; ngx_stream_lua_socket_udp_upstream_t *u; int type; const char *msg; ngx_str_t query; ngx_stream_lua_srv_conf_t *lscf; if (lua_gettop(L) != 2) { return luaL_error(L, "expecting 2 arguments (including the object), " "but got %d", lua_gettop(L)); } s = ngx_stream_lua_get_session(L); if (s == NULL) { return luaL_error(L, "session 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) { lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_lua_module); if (lscf->log_socket_errors) { ngx_log_error(NGX_LOG_ERR, s->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->session != s) { return luaL_error(L, "bad session"); } 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_stream_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_stream_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_stream_upstream_init_session 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_stream_lua_socket_error_retval_handler(s, u, L); } if (n != (ssize_t) query.len) { dd("not the while query was sent"); u->ft_type |= NGX_STREAM_LUA_SOCKET_FT_PARTIALWRITE; return ngx_stream_lua_socket_error_retval_handler(s, u, L); } dd("n == len"); lua_pushinteger(L, 1); return 1; }