static int ngx_http_lua_ngx_set(lua_State *L) { ngx_http_request_t *r; u_char *p; size_t len; /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); if (len == sizeof("status") - 1 && ngx_strncmp(p, "status", sizeof("status") - 1) == 0) { r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } if (r->header_sent) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to set ngx.status after sending out " "response headers"); return 0; } ngx_http_lua_check_fake_request(L, r); /* get the value */ r->headers_out.status = (ngx_uint_t) luaL_checknumber(L, 3); if (r->headers_out.status == 101) { /* * XXX work-around a bug in the Nginx core that 101 does * not have a default status line */ ngx_str_set(&r->headers_out.status_line, "101 Switching Protocols"); } else { r->headers_out.status_line.len = 0; } return 0; } if (len == sizeof("ctx") - 1 && ngx_strncmp(p, "ctx", sizeof("ctx") - 1) == 0) { r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } return ngx_http_lua_ngx_set_ctx(L); } lua_rawset(L, -3); return 0; }
static int ngx_http_lua_ngx_req_http_version(lua_State *L) { ngx_http_request_t *r; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_http_lua_check_fake_request(L, r); switch (r->http_version) { case NGX_HTTP_VERSION_9: lua_pushnumber(L, 0.9); break; case NGX_HTTP_VERSION_10: lua_pushnumber(L, 1.0); break; case NGX_HTTP_VERSION_11: lua_pushnumber(L, 1.1); break; default: lua_pushnil(L); break; } return 1; }
static int ngx_http_lua_socket_udp(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; if (lua_gettop(L) != 0) { return luaL_error(L, "expecting zero arguments, but got %d", lua_gettop(L)); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request 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 | NGX_HTTP_LUA_CONTEXT_TIMER); lua_createtable(L, 3 /* narr */, 1 /* nrec */); lua_pushlightuserdata(L, &ngx_http_lua_socket_udp_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); dd("top: %d", lua_gettop(L)); return 1; }
static int ngx_http_lua_ngx_req_set_keepalive(lua_State *L) { int n; ngx_http_request_t *r; int keepalive; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "only one argument expected but got %d", n); } keepalive = lua_toboolean(L, 1); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } ngx_http_lua_check_fake_request(L, r); r->keepalive = keepalive; return 1; }
static int ngx_http_lua_ngx_req_discard_body(lua_State *L) { ngx_http_request_t *r; ngx_int_t rc; int n; n = lua_gettop(L); if (n != 0) { return luaL_error(L, "expecting 0 arguments but seen %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } ngx_http_lua_check_fake_request(L, r); rc = ngx_http_discard_request_body(r); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return luaL_error(L, "failed to discard request body"); } return 0; }
static int ngx_http_lua_ngx_sleep(lua_State *L) { int n; ngx_int_t delay; /* in msec */ ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; n = lua_gettop(L); if (n != 1) { return luaL_error(L, "attempt to pass %d arguments, but accepted 1", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } delay = (ngx_int_t) (luaL_checknumber(L, 1) * 1000); if (delay < 0) { return luaL_error(L, "invalid sleep duration \"%d\"", delay); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER); coctx = ctx->cur_co_ctx; if (coctx == NULL) { return luaL_error(L, "no co ctx found"); } coctx->data = r; coctx->sleep.handler = ngx_http_lua_sleep_handler; coctx->sleep.data = coctx; coctx->sleep.log = r->connection->log; dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay, (int) r->uri.len, r->uri.data); ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay); ngx_http_lua_cleanup_pending_operation(coctx); coctx->cleanup = ngx_http_lua_sleep_cleanup; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua ready to sleep for %d ms", delay); return lua_yield(L, 0); }
static int ngx_http_lua_ngx_req_set_uri_args(lua_State *L) { ngx_http_request_t *r; ngx_str_t args; const char *msg; size_t len; u_char *p; if (lua_gettop(L) != 1) { return luaL_error(L, "expecting 1 argument but seen %d", lua_gettop(L)); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_http_lua_check_fake_request(L, r); switch (lua_type(L, 1)) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) lua_tolstring(L, 1, &len); args.data = ngx_palloc(r->pool, len); if (args.data == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(args.data, p, len); args.len = len; break; case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, 1, &args); dd("args: %.*s", (int) args.len, args.data); break; default: msg = lua_pushfstring(L, "string, number, or table expected, " "but got %s", luaL_typename(L, 2)); return luaL_argerror(L, 1, msg); } dd("args: %.*s", (int) args.len, args.data); r->args.data = args.data; r->args.len = args.len; r->valid_unparsed_uri = 0; return 0; }
static int ngx_http_lua_uthread_spawn(lua_State *L) { int n; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx = NULL; n = lua_gettop(L); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx); /* anchor the newly created coroutine into the Lua registry */ lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); coctx->co_ref = luaL_ref(L, -2); lua_pop(L, 1); if (n > 1) { lua_replace(L, 1); lua_xmove(L, coctx->co, n - 1); } coctx->is_uthread = 1; ctx->uthreads++; coctx->co_status = NGX_HTTP_LUA_CO_RUNNING; ctx->co_op = NGX_HTTP_LUA_USER_THREAD_RESUME; ctx->cur_co_ctx->thread_spawn_yielded = 1; if (ngx_http_lua_post_thread(r, ctx, ctx->cur_co_ctx) != NGX_OK) { return luaL_error(L, "no memory"); } coctx->parent_co_ctx = ctx->cur_co_ctx; ctx->cur_co_ctx = coctx; ngx_http_lua_probe_user_thread_spawn(r, L, coctx->co); dd("yielding with arg %s, top=%d, index-1:%s", luaL_typename(L, -1), (int) lua_gettop(L), luaL_typename(L, 1)); return lua_yield(L, 1); }
static int ngx_http_lua_on_abort(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx = NULL; ngx_http_lua_loc_conf_t *llcf; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } ngx_http_lua_check_fake_request2(L, r, ctx); if (ctx->on_abort_co_ctx) { lua_pushnil(L); lua_pushliteral(L, "duplicate call"); return 2; } llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (!llcf->check_client_abort) { lua_pushnil(L); lua_pushliteral(L, "lua_check_client_abort is off"); return 2; } ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx); lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushvalue(L, -2); dd("on_wait thread 1: %p", lua_tothread(L, -1)); coctx->co_ref = luaL_ref(L, -2); lua_pop(L, 1); coctx->is_uthread = 1; ctx->on_abort_co_ctx = coctx; dd("on_wait thread 2: %p", coctx->co); coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; coctx->parent_co_ctx = ctx->cur_co_ctx; lua_pushinteger(L, 1); return 1; }
/** * Send last_buf, terminate output stream * */ static int ngx_http_lua_ngx_eof(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } if (lua_gettop(L) != 0) { return luaL_error(L, "no argument is expected"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no ctx found"); } if (ctx->acquired_raw_req_socket) { lua_pushnil(L); lua_pushliteral(L, "raw request socket acquired"); return 2; } if (ctx->eof) { lua_pushnil(L); lua_pushliteral(L, "seen eof"); return 2; } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua send eof"); rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); dd("send chain: %d", (int) rc); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { lua_pushnil(L); lua_pushliteral(L, "nginx output filter error"); return 2; } lua_pushinteger(L, 1); return 1; }
static int ngx_http_lua_ngx_req_is_internal(lua_State *L) { ngx_http_request_t *r; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } lua_pushboolean(L, r->internal == 1); return 1; }
static int ngx_http_lua_ngx_req_get_uri_args(lua_State *L) { ngx_http_request_t *r; u_char *buf; u_char *last; int retval; int n; int max; n = lua_gettop(L); if (n != 0 && n != 1) { return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n); } if (n == 1) { max = luaL_checkinteger(L, 1); lua_pop(L, 1); } else { max = NGX_HTTP_LUA_MAX_ARGS; } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_http_lua_check_fake_request(L, r); lua_createtable(L, 0, 4); /* we copy r->args over to buf to simplify * unescaping query arg keys and values */ buf = ngx_palloc(r->pool, r->args.len); if (buf == NULL) { return luaL_error(L, "no memory"); } ngx_memcpy(buf, r->args.data, r->args.len); last = buf + r->args.len; retval = ngx_http_lua_parse_args(L, buf, last, max); ngx_pfree(r->pool, buf); return retval; }
static int ngx_http_lua_ngx_header_get(lua_State *L) { ngx_http_request_t *r; u_char *p, c; ngx_str_t key; ngx_uint_t i; size_t len; ngx_http_lua_loc_conf_t *llcf; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_http_lua_check_fake_request(L, r); /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); dd("key: %.*s, len %d", (int) len, p, (int) len); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers && memchr(p, '_', len) != NULL) { key.data = (u_char *) lua_newuserdata(L, len); if (key.data == NULL) { return luaL_error(L, "no memory"); } /* replace "_" with "-" */ for (i = 0; i < len; i++) { c = p[i]; if (c == '_') { c = '-'; } key.data[i] = c; } } else { key.data = p; } key.len = len; return ngx_http_lua_get_output_header(L, r, &key); }
static int ngx_http_lua_ngx_timer_pending_count(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_main_conf_t *lmcf; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request"); } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); lua_pushnumber(L, lmcf->pending_timers); return 1; }
static int ngx_http_lua_ngx_header_get(lua_State *L) { ngx_http_request_t *r; u_char *p; ngx_str_t key; ngx_uint_t i; size_t len; ngx_http_lua_loc_conf_t *llcf; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } ngx_http_lua_check_fake_request(L, r); /* we skip the first argument that is the table */ p = (u_char *) luaL_checklstring(L, 2, &len); dd("key: %.*s, len %d", (int) len, p, (int) len); key.data = ngx_palloc(r->pool, len + 1); if (key.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(key.data, p, len); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers) { /* replace "_" with "-" */ for (i = 0; i < len; i++) { if (key.data[i] == '_') { key.data[i] = '-'; } } } key.data[len] = '\0'; key.len = len; return ngx_http_lua_get_output_header(L, r, &key); }
static int ngx_http_lua_coroutine_create(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } return ngx_http_lua_coroutine_create_helper(L, r, ctx, NULL); }
static int ngx_http_lua_coroutine_yield(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER | NGX_HTTP_LUA_CONTEXT_SSL_CERT); coctx = ctx->cur_co_ctx; coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED; ctx->co_op = NGX_HTTP_LUA_USER_CORO_YIELD; if (!coctx->is_uthread && coctx->parent_co_ctx) { dd("set coroutine to running"); coctx->parent_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; ngx_http_lua_probe_user_coroutine_yield(r, coctx->parent_co_ctx->co, L); } else { ngx_http_lua_probe_user_coroutine_yield(r, NULL, L); } /* yield and pass retvals to main thread, * and resume parent coroutine there */ return lua_yield(L, lua_gettop(L)); }
static int ngx_http_lua_socket_udp_close(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_socket_udp_upstream_t *u; if (lua_gettop(L) != 1) { return luaL_error(L, "expecting 1 argument " "(including the object) but seen %d", lua_gettop(L)); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request 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) { lua_pushnil(L); lua_pushliteral(L, "closed"); return 2; } if (u->request != r) { return luaL_error(L, "bad request"); } if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); return 2; } ngx_http_lua_socket_udp_finalize(r, u); lua_pushinteger(L, 1); return 1; }
static int ngx_http_lua_coroutine_status(lua_State *L) { lua_State *co; /* new coroutine to be created */ ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */ co = lua_tothread(L, 1); luaL_argcheck(L, co, 1, "coroutine expected"); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE | NGX_HTTP_LUA_CONTEXT_ACCESS | NGX_HTTP_LUA_CONTEXT_CONTENT | NGX_HTTP_LUA_CONTEXT_TIMER | NGX_HTTP_LUA_CONTEXT_SSL_CERT); coctx = ngx_http_lua_get_co_ctx(co, ctx); if (coctx == NULL) { lua_pushlstring(L, (const char *) ngx_http_lua_co_status_names[NGX_HTTP_LUA_CO_DEAD].data, ngx_http_lua_co_status_names[NGX_HTTP_LUA_CO_DEAD].len); return 1; } dd("co status: %d", coctx->co_status); lua_pushlstring(L, (const char *) ngx_http_lua_co_status_names[coctx->co_status].data, ngx_http_lua_co_status_names[coctx->co_status].len); return 1; }
int ngx_http_lua_ngx_get_ctx(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } if (ctx->ctx_ref == LUA_NOREF) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua create ngx.ctx table for the current request"); lua_pushliteral(L, ngx_http_lua_ctx_tables_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_createtable(L, 0 /* narr */, 4 /* nrec */); lua_pushvalue(L, -1); ctx->ctx_ref = luaL_ref(L, -3); if (ngx_http_lua_ngx_ctx_add_cleanup(r, ctx->ctx_ref) != NGX_OK) { return luaL_error(L, "no memory"); } return 1; } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua fetching existing ngx.ctx table for the current " "request"); lua_pushliteral(L, ngx_http_lua_ctx_tables_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_rawgeti(L, -1, ctx->ctx_ref); return 1; }
static int ngx_http_lua_ngx_req_get_keepalive(lua_State *L) { int n; ngx_http_request_t *r; n = lua_gettop(L); if (n != 0) { return luaL_error(L, "no arguments expected but got %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } ngx_http_lua_check_fake_request(L, r); lua_pushboolean(L, r->keepalive); return 1; }
static int ngx_http_lua_ngx_req_get_method(lua_State *L) { int n; ngx_http_request_t *r; n = lua_gettop(L); if (n != 0) { return luaL_error(L, "only one argument expected but got %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } ngx_http_lua_check_fake_request(L, r); lua_pushlstring(L, (char *) r->method_name.data, r->method_name.len); return 1; }
static int ngx_http_lua_ngx_req_get_body_file(lua_State *L) { ngx_http_request_t *r; int n; n = lua_gettop(L); if (n != 0) { return luaL_error(L, "expecting 0 arguments but seen %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "request object not found"); } ngx_http_lua_check_fake_request(L, r); if (r->request_body == NULL || r->request_body->temp_file == NULL) { lua_pushnil(L); return 1; } dd("XXX file directio: %u, f:%u, m:%u, t:%u, end - pos %d, size %d", r->request_body->temp_file->file.directio, r->request_body->bufs->buf->in_file, r->request_body->bufs->buf->memory, r->request_body->bufs->buf->temporary, (int) (r->request_body->bufs->buf->end - r->request_body->bufs->buf->pos), (int) ngx_buf_size(r->request_body->bufs->buf)); lua_pushlstring(L, (char *) r->request_body->temp_file->file.name.data, r->request_body->temp_file->file.name.len); return 1; }
/** * Send out headers * */ static int ngx_http_lua_ngx_send_headers(lua_State *L) { ngx_int_t rc; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request 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); if (!r->header_sent && !ctx->header_sent) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua send headers"); rc = ngx_http_lua_send_header_if_needed(r, ctx); if (rc == NGX_ERROR || rc > NGX_OK) { lua_pushnil(L); lua_pushliteral(L, "nginx output filter error"); return 2; } } lua_pushinteger(L, 1); return 1; }
static int ngx_http_lua_ngx_location_capture_multi(lua_State *L) { ngx_http_request_t *r; ngx_http_request_t *sr; /* 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; 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, "out of 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; extra_args.data = NULL; extra_args.len = 0; 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 "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, "out of 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, "out of 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, "out of 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; args.data = NULL; args.len = 0; 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, "out of 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, "out of 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, "out of 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 */ ngx_http_lua_init_ctx(sr_ctx); sr_ctx->capture = 1; sr_ctx->index = index; sr_ctx->last_body = &sr_ctx->body; 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_set_ctx(sr, sr_ctx, ngx_http_lua_module); rc = ngx_http_lua_adjust_subrequest(sr, method, 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); }
static int ngx_http_lua_ngx_timer_at(lua_State *L) { int nargs, co_ref; u_char *p; lua_State *mt; /* the main thread */ lua_State *co; ngx_msec_t delay; ngx_event_t *ev; ngx_http_request_t *r; ngx_connection_t *saved_c = NULL; #if 0 ngx_http_connection_t *hc; #endif ngx_http_lua_timer_ctx_t *tctx; ngx_http_lua_main_conf_t *lmcf; #if 0 ngx_http_core_main_conf_t *cmcf; #endif nargs = lua_gettop(L); if (nargs < 2) { return luaL_error(L, "expecting at least 2 arguments but got %d", nargs); } delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000); luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2, "Lua function expected"); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request"); } if (ngx_exiting) { lua_pushnil(L); lua_pushliteral(L, "process exiting"); return 2; } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); if (lmcf->pending_timers >= lmcf->max_pending_timers) { lua_pushnil(L); lua_pushliteral(L, "too many pending timers"); return 2; } if (lmcf->watcher == NULL) { /* create the watcher fake connection */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua creating fake watcher connection"); if (ngx_cycle->files) { saved_c = ngx_cycle->files[0]; } lmcf->watcher = ngx_get_connection(0, ngx_cycle->log); if (ngx_cycle->files) { ngx_cycle->files[0] = saved_c; } if (lmcf->watcher == NULL) { return luaL_error(L, "no memory"); } lmcf->watcher->fd = -2; /* to work around the -1 check in ngx_worker_process_cycle */ lmcf->watcher->idle = 1; lmcf->watcher->read->handler = ngx_http_lua_abort_pending_timers; lmcf->watcher->data = lmcf; } mt = lmcf->lua; co = lua_newthread(mt); /* L stack: time func [args] thread */ ngx_http_lua_probe_user_coroutine_create(r, L, co); lua_createtable(co, 0, 0); /* the new global table */ /* co stack: global_tb */ lua_createtable(co, 0, 1); /* the metatable */ lua_pushvalue(co, LUA_GLOBALSINDEX); lua_setfield(co, -2, "__index"); lua_setmetatable(co, -2); /* co stack: global_tb */ lua_replace(co, LUA_GLOBALSINDEX); /* co stack: <empty> */ dd("stack top: %d", lua_gettop(L)); lua_xmove(mt, L, 1); /* move coroutine from main thread to L */ /* L stack: time func [args] thread */ /* mt stack: empty */ lua_pushvalue(L, 2); /* copy entry function to top of L*/ /* L stack: time func [args] thread func */ lua_xmove(L, co, 1); /* move entry function from L to co */ /* L stack: time func [args] thread */ /* co stack: func */ lua_pushvalue(co, LUA_GLOBALSINDEX); lua_setfenv(co, -2); /* co stack: func */ lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: time func [args] thread corountines */ lua_pushvalue(L, -2); /* L stack: time func [args] thread coroutines thread */ co_ref = luaL_ref(L, -2); lua_pop(L, 1); /* L stack: time func [args] thread */ if (nargs > 2) { lua_pop(L, 1); /* L stack: time func [args] */ lua_xmove(L, co, nargs - 2); /* L stack: time func */ /* co stack: func [args] */ } p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t), r->connection->log); if (p == NULL) { lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); return luaL_error(L, "no memory"); } ev = (ngx_event_t *) p; ngx_memzero(ev, sizeof(ngx_event_t)); p += sizeof(ngx_event_t); tctx = (ngx_http_lua_timer_ctx_t *) p; tctx->premature = 0; tctx->co_ref = co_ref; tctx->co = co; tctx->main_conf = r->main_conf; tctx->srv_conf = r->srv_conf; tctx->loc_conf = r->loc_conf; tctx->lmcf = lmcf; ev->handler = ngx_http_lua_timer_handler; ev->data = tctx; ev->log = ngx_cycle->log; lmcf->pending_timers++; ngx_add_timer(ev, delay); lua_pushinteger(L, 1); return 1; }
static int ngx_http_lua_socket_udp_receive(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_socket_udp_upstream_t *u; ngx_int_t rc; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; size_t size; int nargs; ngx_http_lua_loc_conf_t *llcf; nargs = lua_gettop(L); if (nargs != 1 && nargs != 2) { return luaL_error(L, "expecting 1 or 2 arguments " "(including the object), but got %d", nargs); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request found"); } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket calling receive() method"); 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 receive 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->request != r) { return luaL_error(L, "bad request"); } if (u->ft_type) { u->ft_type = 0; } #if 1 if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); return 2; } #endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket read timeout: %M", u->read_timeout); size = (size_t) luaL_optnumber(L, 2, UDP_MAX_DATAGRAM_SIZE); size = ngx_min(size, UDP_MAX_DATAGRAM_SIZE); u->recv_buf_size = size; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket receive buffer size: %uz", u->recv_buf_size); rc = ngx_http_lua_socket_udp_read(r, u); if (rc == NGX_ERROR) { dd("read failed: %d", (int) u->ft_type); rc = ngx_http_lua_socket_udp_receive_retval_handler(r, u, L); dd("udp receive retval returned: %d", (int) rc); return rc; } if (rc == NGX_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket receive done in a single run"); return ngx_http_lua_socket_udp_receive_retval_handler(r, u, L); } /* n == NGX_AGAIN */ u->read_event_handler = ngx_http_lua_socket_udp_read_handler; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { return luaL_error(L, "no request ctx found"); } coctx = ctx->cur_co_ctx; ngx_http_lua_cleanup_pending_operation(coctx); coctx->cleanup = ngx_http_lua_udp_socket_cleanup; coctx->data = u; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; } else { r->write_event_handler = ngx_http_core_run_phases; } u->co_ctx = coctx; u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_udp_receive_retval_handler; return lua_yield(L, 0); }
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)); } r = ngx_http_lua_get_req(L); 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->request != r) { return luaL_error(L, "bad request"); } 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_socket_udp_setpeername(lua_State *L) { ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_str_t host; int port; ngx_resolver_ctx_t *rctx, temp; ngx_http_core_loc_conf_t *clcf; int saved_top; int n; u_char *p; size_t len; ngx_url_t url; ngx_int_t rc; ngx_http_lua_loc_conf_t *llcf; ngx_udp_connection_t *uc; int timeout; ngx_http_lua_co_ctx_t *coctx; ngx_http_lua_socket_udp_upstream_t *u; /* * TODO: we should probably accept an extra argument to setpeername() * to allow the user bind the datagram unix domain socket himself, * which is necessary for systems without autobind support. */ n = lua_gettop(L); if (n != 2 && n != 3) { return luaL_error(L, "ngx.socket.udp setpeername: expecting 2 or 3 " "arguments (including the object), but seen %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request 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 | NGX_HTTP_LUA_CONTEXT_TIMER); luaL_checktype(L, 1, LUA_TTABLE); p = (u_char *) luaL_checklstring(L, 2, &len); host.data = ngx_palloc(r->pool, len + 1); if (host.data == NULL) { return luaL_error(L, "no memory"); } host.len = len; ngx_memcpy(host.data, p, len); host.data[len] = '\0'; if (n == 3) { port = luaL_checkinteger(L, 3); if (port < 0 || port > 65536) { lua_pushnil(L); lua_pushfstring(L, "bad port number: %d", port); return 2; } } else { /* n == 2 */ port = 0; } lua_rawgeti(L, 1, SOCKET_CTX_INDEX); u = lua_touserdata(L, -1); lua_pop(L, 1); if (u) { if (u->request && u->request != r) { return luaL_error(L, "bad request"); } if (u->waiting) { lua_pushnil(L); lua_pushliteral(L, "socket busy"); return 2; } if (u->udp_connection.connection) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket reconnect without shutting down"); ngx_http_lua_socket_udp_finalize(r, u); } ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua reuse socket upstream ctx"); } else { u = lua_newuserdata(L, sizeof(ngx_http_lua_socket_udp_upstream_t)); if (u == NULL) { return luaL_error(L, "no memory"); } #if 1 lua_pushlightuserdata(L, &ngx_http_lua_udp_udata_metatable_key); lua_rawget(L, LUA_REGISTRYINDEX); lua_setmetatable(L, -2); #endif lua_rawseti(L, 1, SOCKET_CTX_INDEX); } ngx_memzero(u, sizeof(ngx_http_lua_socket_udp_upstream_t)); u->request = r; /* set the controlling request */ llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); u->conf = llcf; uc = &u->udp_connection; uc->log = *r->connection->log; dd("lua peer connection log: %p", &uc->log); lua_rawgeti(L, 1, SOCKET_TIMEOUT_INDEX); timeout = (ngx_int_t) lua_tointeger(L, -1); lua_pop(L, 1); if (timeout > 0) { u->read_timeout = (ngx_msec_t) timeout; } else { u->read_timeout = u->conf->read_timeout; } ngx_memzero(&url, sizeof(ngx_url_t)); url.url.len = host.len; url.url.data = host.data; url.default_port = (in_port_t) port; url.no_resolve = 1; if (ngx_parse_url(r->pool, &url) != NGX_OK) { lua_pushnil(L); if (url.err) { lua_pushfstring(L, "failed to parse host name \"%s\": %s", host.data, url.err); } else { lua_pushfstring(L, "failed to parse host name \"%s\"", host.data); } return 2; } u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); if (u->resolved == NULL) { return luaL_error(L, "no memory"); } if (url.addrs && url.addrs[0].sockaddr) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket network address given directly"); u->resolved->sockaddr = url.addrs[0].sockaddr; u->resolved->socklen = url.addrs[0].socklen; u->resolved->naddrs = 1; u->resolved->host = url.addrs[0].name; } else { u->resolved->host = host; u->resolved->port = (in_port_t) port; } if (u->resolved->sockaddr) { rc = ngx_http_lua_socket_resolve_retval_handler(r, u, L); if (rc == NGX_AGAIN) { return lua_yield(L, 0); } return rc; } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); temp.name = host; rctx = ngx_resolve_start(clcf->resolver, &temp); if (rctx == NULL) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; lua_pushnil(L); lua_pushliteral(L, "failed to start the resolver"); return 2; } if (rctx == NGX_NO_RESOLVER) { u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; lua_pushnil(L); lua_pushfstring(L, "no resolver defined to resolve \"%s\"", host.data); return 2; } rctx->name = host; #if !defined(nginx_version) || nginx_version < 1005008 rctx->type = NGX_RESOLVE_A; #endif rctx->handler = ngx_http_lua_socket_resolve_handler; rctx->data = u; rctx->timeout = clcf->resolver_timeout; u->co_ctx = ctx->cur_co_ctx; u->resolved->ctx = rctx; saved_top = lua_gettop(L); coctx = ctx->cur_co_ctx; ngx_http_lua_cleanup_pending_operation(coctx); coctx->cleanup = ngx_http_lua_udp_resolve_cleanup; if (ngx_resolve_name(rctx) != NGX_OK) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua udp socket fail to run resolver immediately"); u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; u->resolved->ctx = NULL; lua_pushnil(L); lua_pushfstring(L, "%s could not be resolved", host.data); return 2; } if (u->waiting == 1) { /* resolved and already connecting */ return lua_yield(L, 0); } n = lua_gettop(L) - saved_top; if (n) { /* errors occurred during resolving or connecting * or already connected */ return n; } /* still resolving */ u->waiting = 1; u->prepare_retvals = ngx_http_lua_socket_resolve_retval_handler; coctx->data = u; if (ctx->entered_content_phase) { r->write_event_handler = ngx_http_lua_content_wev_handler; } else { r->write_event_handler = ngx_http_core_run_phases; } return lua_yield(L, 0); }
static int ngx_http_lua_ngx_exec(lua_State *L) { int n; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_str_t uri; ngx_str_t args, user_args; ngx_uint_t flags; u_char *p; u_char *q; size_t len; const char *msg; n = lua_gettop(L); if (n != 1 && n != 2) { return luaL_error(L, "expecting one or two arguments, but got %d", n); } r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } args.data = NULL; args.len = 0; /* read the 1st argument (uri) */ p = (u_char *) luaL_checklstring(L, 1, &len); if (len == 0) { return luaL_error(L, "The uri argument is empty"); } uri.data = ngx_palloc(r->pool, len); if (uri.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(uri.data, p, len); uri.len = len; 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); ngx_http_lua_check_if_abortable(L, ctx); if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (n == 2) { /* read the 2nd argument (args) */ dd("args type: %s", luaL_typename(L, 2)); switch (lua_type(L, 2)) { case LUA_TNUMBER: case LUA_TSTRING: p = (u_char *) lua_tolstring(L, 2, &len); user_args.data = ngx_palloc(r->pool, len); if (user_args.data == NULL) { return luaL_error(L, "out of memory"); } ngx_memcpy(user_args.data, p, len); user_args.len = len; break; case LUA_TTABLE: ngx_http_lua_process_args_option(r, L, 2, &user_args); dd("user_args: %.*s", (int) user_args.len, user_args.data); break; case LUA_TNIL: user_args.data = NULL; user_args.len = 0; break; default: msg = lua_pushfstring(L, "string, number, or table expected, " "but got %s", luaL_typename(L, 2)); return luaL_argerror(L, 2, msg); } } else { user_args.data = NULL; user_args.len = 0; } if (user_args.len) { if (args.len == 0) { args = user_args; } else { p = ngx_palloc(r->pool, args.len + user_args.len + 1); if (p == NULL) { return luaL_error(L, "out of memory"); } q = ngx_copy(p, args.data, args.len); *q++ = '&'; ngx_memcpy(q, user_args.data, user_args.len); args.data = p; args.len += user_args.len + 1; } } if (r->header_sent) { return luaL_error(L, "attempt to call ngx.exec after " "sending out response headers"); } ctx->exec_uri = uri; ctx->exec_args = args; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua exec \"%V?%V\"", &ctx->exec_uri, &ctx->exec_args); return lua_yield(L, 0); }