static ngx_int_t ngx_http_lua_header_filter(ngx_http_request_t *r) { ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; ngx_http_cleanup_t *cln; uint8_t old_context; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua header filter for user lua code, uri \"%V\"", &r->uri); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->body_filter_handler) { r->filter_need_in_memory = 1; } if (llcf->header_filter_handler == NULL) { dd("no header filter handler found"); return ngx_http_next_header_filter(r); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } } if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_ERROR; } cln->handler = ngx_http_lua_request_cleanup; cln->data = r; ctx->cleanup = &cln->handler; } old_context = ctx->context; ctx->context = NGX_HTTP_LUA_CONTEXT_HEADER_FILTER; dd("calling header filter handler"); rc = llcf->header_filter_handler(r); ctx->context = old_context; if (rc != NGX_OK) { dd("calling header filter handler rc %d", (int)rc); return NGX_ERROR; } return ngx_http_next_header_filter(r); }
static ngx_int_t ngx_http_lua_set_by_lua_init(ngx_http_request_t *r) { lua_State *L; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } } else { L = ngx_http_lua_get_lua_vm(r, ctx); ngx_http_lua_reset_ctx(r, L, ctx); } if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_ERROR; } cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = ctx; ctx->cleanup = &cln->handler; } ctx->context = NGX_HTTP_LUA_CONTEXT_SET; return NGX_OK; }
ngx_int_t ngx_http_lua_log_handler(ngx_http_request_t *r) { ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua log handler, uri:\"%V\" c:%ud", &r->uri, r->main->count); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_handler == NULL) { dd("no log handler found"); return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } } ctx->context = NGX_HTTP_LUA_CONTEXT_LOG; dd("calling log handler"); return llcf->log_handler(r); }
ngx_int_t ngx_http_lua_log_handler(ngx_http_request_t *r) { ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_loc_conf_t *llcf; ngx_int_t rc; lua_State *L; ngx_http_lua_ctx_t *ctx; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua log handler, uri:\"%V\" c:%ud", &r->uri, r->main->count); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_handler == NULL) { dd("no log handler found"); return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } } ctx->context = NGX_HTTP_LUA_CONTEXT_LOG; dd("calling log handler"); rc = llcf->log_handler(r); /* we must release the ngx.ctx table here because request cleanup runs * before log phase handlers */ if (ctx->ctx_ref != LUA_NOREF) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua release ngx.ctx"); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); L = lmcf->lua; lua_pushlightuserdata(L, &ngx_http_lua_ctx_tables_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, ctx->ctx_ref); ctx->ctx_ref = LUA_NOREF; lua_pop(L, 1); } return rc; }
ngx_int_t ngx_http_lua_log_handler(ngx_http_request_t *r) { ngx_http_lua_loc_conf_t *llcf; ngx_int_t rc; lua_State *L; ngx_http_lua_ctx_t *ctx; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua log handler, uri:\"%V\" c:%ud", &r->uri, r->main->count); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_handler == NULL) { dd("no log handler found"); return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } } ctx->context = NGX_HTTP_LUA_CONTEXT_LOG; dd("calling log handler"); rc = llcf->log_handler(r); /* we must release the ngx.ctx table here because request cleanup runs * before log phase handlers */ if (ctx->ctx_ref != LUA_NOREF) { L = ngx_http_lua_get_lua_vm(r, ctx); ngx_http_lua_release_ngx_ctx_table(r->connection->log, L, ctx); } return rc; }
static ngx_int_t ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) { lua_State *L; ngx_int_t rc; ngx_http_request_t *r; ngx_http_lua_ctx_t *ctx; ngx_http_lua_srv_conf_t *lscf; ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_balancer_peer_data_t *bp = data; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "lua balancer peer, tries: %ui", pc->tries); lscf = bp->conf; r = bp->request; ngx_http_lua_assert(lscf->balancer.handler && r); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } L = ngx_http_lua_get_lua_vm(r, ctx); } else { L = ngx_http_lua_get_lua_vm(r, ctx); dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); } ctx->context = NGX_HTTP_LUA_CONTEXT_BALANCER; bp->sockaddr = NULL; bp->socklen = 0; bp->more_tries = 0; bp->total_tries++; lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); /* balancer_by_lua does not support yielding and * there cannot be any conflicts among concurrent requests, * thus it is safe to store the peer data in the main conf. */ lmcf->balancer_peer_data = bp; rc = lscf->balancer.handler(r, lscf, L); if (rc == NGX_ERROR) { return NGX_ERROR; } if (ctx->exited && ctx->exit_code != NGX_OK) { rc = ctx->exit_code; if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED #ifdef HAVE_BALANCER_STATUS_CODE_PATCH || rc >= NGX_HTTP_SPECIAL_RESPONSE #endif ) { return rc; } if (rc > NGX_OK) { return NGX_ERROR; } } if (bp->sockaddr && bp->socklen) { pc->sockaddr = bp->sockaddr; pc->socklen = bp->socklen; pc->cached = 0; pc->connection = NULL; pc->name = bp->host; bp->rrp.peers->single = 0; if (bp->more_tries) { r->upstream->peer.tries += bp->more_tries; } dd("tries: %d", (int) r->upstream->peer.tries); return NGX_OK; } return ngx_http_upstream_get_round_robin_peer(pc, &bp->rrp); }
ngx_int_t ngx_http_lua_access_handler(ngx_http_request_t *r) { ngx_int_t rc; ngx_http_lua_ctx_t *ctx; ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_main_conf_t *lmcf; ngx_http_phase_handler_t tmp, *ph, *cur_ph, *last_ph; ngx_http_core_main_conf_t *cmcf; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua access handler, uri \"%V\"", &r->uri); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); if (!lmcf->postponed_to_access_phase_end) { lmcf->postponed_to_access_phase_end = 1; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ph = cmcf->phase_engine.handlers; cur_ph = &ph[r->phase_handler]; /* we should skip the post_access phase handler here too */ last_ph = &ph[cur_ph->next - 2]; dd("ph cur: %d, ph next: %d", (int) r->phase_handler, (int) (cur_ph->next - 2)); #if 0 if (cur_ph == last_ph) { dd("XXX our handler is already the last access phase handler"); } #endif if (cur_ph < last_ph) { dd("swaping the contents of cur_ph and last_ph..."); tmp = *cur_ph; memmove(cur_ph, cur_ph + 1, (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t)); *last_ph = tmp; r->phase_handler--; /* redo the current ph */ return NGX_DECLINED; } } llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->access_handler == NULL) { dd("no access handler found"); return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } dd("entered? %d", (int) ctx->entered_access_phase); if (ctx->entered_access_phase) { dd("calling wev handler"); rc = ctx->resume_handler(r); dd("wev handler returns %d", (int) rc); if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) { return rc; } return NGX_DECLINED; } if (ctx->waiting_more_body) { dd("WAITING MORE BODY"); return NGX_DONE; } if (llcf->force_read_body && !ctx->read_body_done) { r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; rc = ngx_http_read_client_request_body(r, ngx_http_lua_generic_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; } if (rc == NGX_AGAIN) { ctx->waiting_more_body = 1; return NGX_DONE; } } dd("calling access handler"); return llcf->access_handler(r); }
ngx_int_t ngx_http_lua_log_handler(ngx_http_request_t *r) { #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) ngx_uint_t trim_cycle, trim_nreq; ngx_http_lua_main_conf_t *lmcf; #endif ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; #if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM) lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); trim_cycle = lmcf->malloc_trim_cycle; if (trim_cycle > 0) { dd("cycle: %d", (int) trim_cycle); trim_nreq = ++lmcf->malloc_trim_req_count; if (trim_nreq >= trim_cycle) { lmcf->malloc_trim_req_count = 0; #if (NGX_DEBUG) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "malloc_trim(1) returned %d", malloc_trim(1)); #else (void) malloc_trim(1); #endif } } # if (NGX_DEBUG) else { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "malloc_trim() disabled"); } # endif #endif ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua log handler, uri:\"%V\" c:%ud", &r->uri, r->main->count); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->log_handler == NULL) { dd("no log handler found"); return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } } ctx->context = NGX_HTTP_LUA_CONTEXT_LOG; dd("calling log handler"); return llcf->log_handler(r); }
ngx_int_t ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ngx_http_lua_loc_conf_t *llcf; dd("content by chunk"); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } else { dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); } ctx->entered_content_phase = 1; /* {{{ new coroutine to handle request */ co = ngx_http_lua_new_thread(r, L, &co_ref); if (co == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } /* move code closure to new coroutine */ lua_xmove(L, co, 1); /* set closure's env table to new coroutine's globals table */ lua_pushvalue(co, LUA_GLOBALSINDEX); lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ ngx_http_lua_set_req(co, r); ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->cur_co_ctx->co_ref = co_ref; /* {{{ register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = r; ctx->cleanup = &cln->handler; } /* }}} */ ctx->context = NGX_HTTP_LUA_CONTEXT_CONTENT; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->check_client_abort) { r->read_event_handler = ngx_http_lua_rd_check_broken_connection; } else { r->read_event_handler = ngx_http_block_reading; } rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc >= NGX_OK) { return rc; } if (rc == NGX_AGAIN) { return ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); } if (rc == NGX_DONE) { return ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); } return NGX_OK; }
ngx_int_t ngx_http_lua_init_worker(ngx_cycle_t *cycle) { char *rv; void *cur, *prev; ngx_uint_t i; ngx_conf_t conf; ngx_cycle_t *fake_cycle; ngx_open_file_t *file, *ofile; ngx_list_part_t *part; ngx_connection_t *c = NULL; ngx_http_module_t *module; ngx_http_request_t *r = NULL; ngx_http_lua_ctx_t *ctx; ngx_http_conf_ctx_t *conf_ctx, http_ctx; ngx_http_lua_loc_conf_t *llcf, *top_llcf; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf, *top_clcf; lmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_lua_module); if (lmcf == NULL || lmcf->init_worker_handler == NULL || lmcf->lua == NULL) { return NGX_OK; } conf_ctx = ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]); http_ctx.main_conf = conf_ctx->main_conf; top_clcf = conf_ctx->loc_conf[ngx_http_core_module.ctx_index]; top_llcf = conf_ctx->loc_conf[ngx_http_lua_module.ctx_index]; ngx_memzero(&conf, sizeof(ngx_conf_t)); conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, cycle->log); if (conf.temp_pool == NULL) { return NGX_ERROR; } conf.temp_pool->log = cycle->log; /* we fake a temporary ngx_cycle_t here because some * modules' merge conf handler may produce side effects in * cf->cycle (like ngx_proxy vs cf->cycle->paths). * also, we cannot allocate our temp cycle on the stack * because some modules like ngx_http_core_module reference * addresses within cf->cycle (i.e., via "&cf->cycle->new_log") */ fake_cycle = ngx_palloc(cycle->pool, sizeof(ngx_cycle_t)); if (fake_cycle == NULL) { goto failed; } ngx_memcpy(fake_cycle, cycle, sizeof(ngx_cycle_t)); #if defined(nginx_version) && nginx_version >= 9007 ngx_queue_init(&fake_cycle->reusable_connections_queue); #endif if (ngx_array_init(&fake_cycle->listening, cycle->pool, cycle->listening.nelts || 1, sizeof(ngx_listening_t)) != NGX_OK) { goto failed; } #if defined(nginx_version) && nginx_version >= 1003007 if (ngx_array_init(&fake_cycle->paths, cycle->pool, cycle->paths.nelts || 1, sizeof(ngx_path_t *)) != NGX_OK) { goto failed; } #endif part = &cycle->open_files.part; ofile = part->elts; if (ngx_list_init(&fake_cycle->open_files, cycle->pool, part->nelts || 1, sizeof(ngx_open_file_t)) != NGX_OK) { goto failed; } for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; ofile = part->elts; i = 0; } file = ngx_list_push(&fake_cycle->open_files); if (file == NULL) { goto failed; } ngx_memcpy(file, ofile, sizeof(ngx_open_file_t)); } if (ngx_list_init(&fake_cycle->shared_memory, cycle->pool, 1, sizeof(ngx_shm_zone_t)) != NGX_OK) { goto failed; } conf.ctx = &http_ctx; conf.cycle = fake_cycle; conf.pool = fake_cycle->pool; conf.log = cycle->log; http_ctx.loc_conf = ngx_pcalloc(conf.pool, sizeof(void *) * ngx_http_max_module); if (http_ctx.loc_conf == NULL) { return NGX_ERROR; } http_ctx.srv_conf = ngx_pcalloc(conf.pool, sizeof(void *) * ngx_http_max_module); if (http_ctx.srv_conf == NULL) { return NGX_ERROR; } for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_HTTP_MODULE) { continue; } module = ngx_modules[i]->ctx; if (module->create_srv_conf) { cur = module->create_srv_conf(&conf); if (cur == NULL) { return NGX_ERROR; } if (module->merge_srv_conf) { prev = module->create_srv_conf(&conf); if (prev == NULL) { return NGX_ERROR; } rv = module->merge_srv_conf(&conf, prev, cur); if (rv != NGX_CONF_OK) { goto failed; } } http_ctx.srv_conf[ngx_modules[i]->ctx_index] = cur; } if (module->create_loc_conf) { cur = module->create_loc_conf(&conf); if (cur == NULL) { return NGX_ERROR; } if (module->merge_loc_conf) { prev = module->create_loc_conf(&conf); if (prev == NULL) { return NGX_ERROR; } rv = module->merge_loc_conf(&conf, prev, cur); if (rv != NGX_CONF_OK) { goto failed; } } http_ctx.loc_conf[ngx_modules[i]->ctx_index] = cur; } } ngx_destroy_pool(conf.temp_pool); conf.temp_pool = NULL; c = ngx_http_lua_create_fake_connection(NULL); if (c == NULL) { goto failed; } c->log->handler = ngx_http_lua_log_init_worker_error; r = ngx_http_lua_create_fake_request(c); if (r == NULL) { goto failed; } r->main_conf = http_ctx.main_conf; r->srv_conf = http_ctx.srv_conf; r->loc_conf = http_ctx.loc_conf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); #if defined(nginx_version) && nginx_version >= 1003014 ngx_http_set_connection_log(r->connection, clcf->error_log); #else c->log->file = clcf->error_log->file; if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { c->log->log_level = clcf->error_log->log_level; } #endif if (top_clcf->resolver) { clcf->resolver = top_clcf->resolver; } ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { goto failed; } ctx->context = NGX_HTTP_LUA_CONTEXT_INIT_WORKER; ctx->cur_co_ctx = NULL; r->read_event_handler = ngx_http_block_reading; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (top_llcf->log_socket_errors != NGX_CONF_UNSET) { llcf->log_socket_errors = top_llcf->log_socket_errors; } ngx_http_lua_set_req(lmcf->lua, r); (void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua); ngx_destroy_pool(c->pool); return NGX_OK; failed: if (conf.temp_pool) { ngx_destroy_pool(conf.temp_pool); } if (c) { ngx_http_lua_close_fake_connection(c); } return NGX_ERROR; }
/* initialize lua coroutine for caching new SSL session */ static ngx_int_t ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) { size_t len; u_char *err_msg; ngx_int_t rc; ngx_http_lua_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } else { dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); } ctx->entered_content_phase = 1; ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE; /* init nginx context in Lua VM */ ngx_http_lua_set_req(L, r); ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */); /* {{{ make new env inheriting main thread's globals table */ lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */ ngx_http_lua_get_globals_table(L); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */ /* }}} */ lua_setfenv(L, -2); /* set new running env for the code closure */ lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ /* protected call user code */ rc = lua_pcall(L, 0, 1, 1); lua_remove(L, 1); /* remove traceback function */ dd("rc == %d", (int) rc); if (rc != 0) { /* error occured when running loaded code */ err_msg = (u_char *) lua_tolstring(L, -1, &len); if (err_msg == NULL) { err_msg = (u_char *) "unknown reason"; len = sizeof("unknown reason") - 1; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to run session_store_by_lua*: %*s", len, err_msg); lua_settop(L, 0); /* clear remaining elems on stack */ ngx_http_lua_finalize_request(r, rc); return NGX_ERROR; } lua_settop(L, 0); /* clear remaining elems on stack */ ngx_http_lua_finalize_request(r, rc); return rc; }
ngx_int_t ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val, ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *script) { size_t i; ngx_int_t rc; u_char *err_msg; size_t len; u_char *data; #if (NGX_PCRE) ngx_pool_t *old_pool; #endif ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; dd("nargs: %d", (int) nargs); ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } } else { ngx_http_lua_reset_ctx(r, L, ctx); } if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_ERROR; } cln->handler = ngx_http_lua_request_cleanup; cln->data = r; ctx->cleanup = &cln->handler; } ctx->context = NGX_HTTP_LUA_CONTEXT_SET; dd("set Lua VM panic handler"); lua_atpanic(L, ngx_http_lua_atpanic); NGX_LUA_EXCEPTION_TRY { dd("initialize nginx context in Lua VM, code chunk at " "stack top sp = 1"); ngx_http_lua_set_by_lua_env(L, r, nargs, args); /* passing directive arguments to the user code */ for (i = 0; i < nargs; i++) { lua_pushlstring(L, (const char *) args[i].data, args[i].len); } #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ old_pool = ngx_http_lua_pcre_malloc_init(r->pool); #endif lua_pushcfunction(L, ngx_http_lua_traceback); lua_insert(L, 1); /* put it under chunk and args */ dd("protected call user code"); rc = lua_pcall(L, nargs, 1, 1); dd("after protected call user code"); lua_remove(L, 1); /* remove traceback function */ #if (NGX_PCRE) /* XXX: work-around to nginx regex subsystem */ ngx_http_lua_pcre_malloc_done(old_pool); #endif if (rc != 0) { /* error occured when running loaded code */ err_msg = (u_char *) lua_tolstring(L, -1, &len); if (err_msg == NULL) { err_msg = (u_char *) "unknown reason"; len = sizeof("unknown reason") - 1; } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "failed to run set_by_lua*: %*s", len, err_msg); lua_settop(L, 0); /* clear remaining elems on stack */ return NGX_ERROR; } data = (u_char *) lua_tolstring(L, -1, &len); if (data) { val->data = ngx_palloc(r->pool, len); if (val->data == NULL) { return NGX_ERROR; } ngx_memcpy(val->data, data, len); val->len = len; } else { val->data = NULL; val->len = 0; } } NGX_LUA_EXCEPTION_CATCH { dd("nginx execution restored"); return NGX_ERROR; } /* clear Lua stack */ lua_settop(L, 0); return NGX_OK; }
static ngx_int_t ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; uint16_t old_context; ngx_http_cleanup_t *cln; lua_State *L; ngx_buf_t *b; ngx_chain_t *out, *cl; ngx_buf_tag_t tag; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua body filter for user lua code, uri \"%V\"", &r->uri); if (in == NULL) { return ngx_http_next_body_filter(r, in); } llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->body_filter_handler == NULL) { dd("no body filter handler found"); return ngx_http_next_body_filter(r, in); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } } if (ctx->seen_last_in_filter) { for (/* void */; in; in = in->next) { dd("mark the buf as consumed: %d", (int) ngx_buf_size(in->buf)); in->buf->pos = in->buf->last; in->buf->file_pos = in->buf->file_last; } return NGX_OK; } if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_ERROR; } cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = ctx; ctx->cleanup = &cln->handler; } old_context = ctx->context; ctx->context = NGX_HTTP_LUA_CONTEXT_BODY_FILTER; dd("calling body filter handler"); rc = llcf->body_filter_handler(r, in); dd("calling body filter handler returned %d", (int) rc); ctx->context = old_context; if (rc != NGX_OK) { return NGX_ERROR; } L = ngx_http_lua_get_lua_vm(r, ctx); lua_getglobal(L, ngx_http_lua_chain_key); out = lua_touserdata(L, -1); lua_pop(L, 1); #if 1 for (cl = out; cl; cl = cl->next) { b = cl->buf; if (b->last == b->pos && !b->last_buf && !b->last_in_chain) { /* skip leading zero-size bufs because they can stuck in the buffer * of ngx_http_write_filter_module (that is, being busy) but get * still recycled by the buffer generator * (usually being the content handler module) at the same * time, which can lead to buffer corruptions. */ /* FIXME we should handle the "flush" flag properly here * now we just discard it if it is set in these zero-size bufs. */ continue; } break; } #endif if (in == out) { return ngx_http_next_body_filter(r, cl); } /* in != out */ rc = ngx_http_next_body_filter(r, cl); if (rc == NGX_ERROR) { return NGX_ERROR; } tag = (ngx_buf_tag_t) &ngx_http_lua_module; #if nginx_version >= 1001004 ngx_chain_update_chains(r->pool, #else ngx_chain_update_chains( #endif &ctx->free_bufs, &ctx->busy_bufs, &out, tag); return rc; }
/* initialize lua coroutine for fetching cached session */ static ngx_int_t ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; ngx_int_t rc; lua_State *co; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); return rc; } } else { dd("reset ctx"); ngx_http_lua_reset_ctx(r, L, ctx); } ctx->entered_content_phase = 1; /* {{{ new coroutine to handle request */ co = ngx_http_lua_new_thread(r, L, &co_ref); if (co == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); return rc; } /* move code closure to new coroutine */ lua_xmove(L, co, 1); /* set closure's env table to new coroutine's globals table */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); /* save nginx request in coroutine globals table */ ngx_http_lua_set_req(co, r); ctx->cur_co_ctx = &ctx->entry_co_ctx; ctx->cur_co_ctx->co = co; ctx->cur_co_ctx->co_ref = co_ref; #ifdef NGX_LUA_USE_ASSERT ctx->cur_co_ctx->co_top = 1; #endif /* register request cleanup hooks */ if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { rc = NGX_ERROR; ngx_http_lua_finalize_request(r, rc); return rc; } cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = ctx; ctx->cleanup = &cln->handler; } ctx->context = NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH; rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc >= NGX_OK) { /* do nothing */ } else if (rc == NGX_AGAIN) { rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); } else if (rc == NGX_DONE) { rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); } else { rc = NGX_OK; } ngx_http_lua_finalize_request(r, rc); return rc; }
static void ngx_http_lua_timer_handler(ngx_event_t *ev) { int n; lua_State *L; ngx_int_t rc; ngx_log_t *log; ngx_connection_t *c = NULL, *saved_c = NULL; ngx_http_request_t *r = NULL; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ngx_http_log_ctx_t *logctx; ngx_http_lua_timer_ctx_t tctx; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua ngx.timer expired"); ngx_memcpy(&tctx, ev->data, sizeof(ngx_http_lua_timer_ctx_t)); ngx_free(ev); ev = NULL; lmcf = tctx.lmcf; lmcf->pending_timers--; if (lmcf->running_timers >= lmcf->max_running_timers) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "%i lua_max_running_timers are not enough", lmcf->max_running_timers); goto abort; } /* create the fake connection (we temporarily use a valid fd (0) to make ngx_get_connection happy) */ if (ngx_cycle->files) { saved_c = ngx_cycle->files[0]; } c = ngx_get_connection(0, ngx_cycle->log); if (ngx_cycle->files) { ngx_cycle->files[0] = saved_c; } if (c == NULL) { goto abort; } c->fd = -1; c->pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, c->log); if (c->pool == NULL) { goto abort; } log = ngx_pcalloc(c->pool, sizeof(ngx_log_t)); if (log == NULL) { goto abort; } logctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); if (logctx == NULL) { goto abort; } dd("c pool allocated: %d", (int) (sizeof(ngx_log_t) + sizeof(ngx_http_log_ctx_t) + sizeof(ngx_http_request_t))); logctx->connection = c; logctx->request = NULL; logctx->current_request = NULL; c->log = log; c->log->connection = c->number; c->log->handler = ngx_http_lua_log_timer_error; c->log->data = logctx; c->log->action = NULL; c->log_error = NGX_ERROR_INFO; #if 0 c->buffer = ngx_create_temp_buf(c->pool, 2); if (c->buffer == NULL) { goto abort; } c->buffer->start[0] = CR; c->buffer->start[1] = LF; #endif /* create the fake request */ r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)); if (r == NULL) { goto abort; } c->requests++; logctx->request = r; logctx->current_request = r; r->pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, c->log); if (r->pool == NULL) { goto abort; } dd("r pool allocated: %d", (int) (sizeof(ngx_http_lua_ctx_t) + sizeof(void *) * ngx_http_max_module + sizeof(ngx_http_cleanup_t))); #if 0 hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); if (hc == NULL) { goto abort; } r->header_in = c->buffer; r->header_end = c->buffer->start; if (ngx_list_init(&r->headers_out.headers, r->pool, 0, sizeof(ngx_table_elt_t)) != NGX_OK) { goto abort; } if (ngx_list_init(&r->headers_in.headers, r->pool, 0, sizeof(ngx_table_elt_t)) != NGX_OK) { goto abort; } #endif r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); if (r->ctx == NULL) { goto abort; } #if 0 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts * sizeof(ngx_http_variable_value_t)); if (r->variables == NULL) { goto abort; } #endif ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { goto abort; } r->headers_in.content_length_n = 0; c->data = r; #if 0 hc->request = r; r->http_connection = hc; #endif r->signature = NGX_HTTP_MODULE; r->connection = c; r->main = r; r->count = 1; r->method = NGX_HTTP_UNKNOWN; r->headers_in.keep_alive_n = -1; r->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; r->subrequests = NGX_HTTP_MAX_SUBREQUESTS + 1; r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE; r->discard_body = 1; r->main_conf = tctx.main_conf; r->srv_conf = tctx.srv_conf; r->loc_conf = tctx.loc_conf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); c->log->file = clcf->error_log->file; if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { c->log->log_level = clcf->error_log->log_level; } c->error = 1; ctx->cur_co_ctx = &ctx->entry_co_ctx; L = lmcf->lua; cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { goto abort; } cln->handler = ngx_http_lua_request_cleanup; cln->data = r; ctx->cleanup = &cln->handler; ctx->entered_content_phase = 1; ctx->context = NGX_HTTP_LUA_CONTEXT_TIMER; r->read_event_handler = ngx_http_block_reading; ctx->cur_co_ctx->co_ref = tctx.co_ref; ctx->cur_co_ctx->co = tctx.co; ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; dd("r connection: %p, log %p", r->connection, r->connection->log); /* save the request in coroutine globals table */ ngx_http_lua_set_req(tctx.co, r); lmcf->running_timers++; lua_pushboolean(tctx.co, tctx.premature); n = lua_gettop(tctx.co); if (n > 2) { lua_insert(tctx.co, 2); } rc = ngx_http_lua_run_thread(L, r, ctx, n - 1); dd("timer lua run thread: %d", (int) rc); if (rc == NGX_ERROR || rc >= NGX_OK) { /* do nothing */ } else if (rc == NGX_AGAIN) { rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); } else if (rc == NGX_DONE) { rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); } else { rc = NGX_OK; } ngx_http_lua_finalize_request(r, rc); return; abort: if (tctx.co_ref && tctx.co) { lua_pushlightuserdata(tctx.co, &ngx_http_lua_coroutines_key); lua_rawget(tctx.co, LUA_REGISTRYINDEX); luaL_unref(tctx.co, -1, tctx.co_ref); lua_settop(tctx.co, 0); } if (r && r->pool) { ngx_destroy_pool(r->pool); } if (c) { ngx_http_lua_close_fake_connection(c); } }
ngx_int_t ngx_http_lua_content_handler(ngx_http_request_t *r) { ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua content handler, uri:\"%V\" c:%ud", &r->uri, r->main->count); llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->content_handler == NULL) { dd("no content handler found"); return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } dd("entered? %d", (int) ctx->entered_content_phase); if (ctx->waiting_more_body) { return NGX_DONE; } if (ctx->entered_content_phase) { dd("calling wev handler"); rc = ctx->resume_handler(r); dd("wev handler returns %d", (int) rc); return rc; } if (llcf->force_read_body && !ctx->read_body_done) { r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; rc = ngx_http_read_client_request_body(r, ngx_http_lua_content_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { #if (nginx_version < 1002006) || \ (nginx_version >= 1003000 && nginx_version < 1003009) r->main->count--; #endif return rc; } if (rc == NGX_AGAIN) { ctx->waiting_more_body = 1; return NGX_DONE; } } dd("setting entered"); ctx->entered_content_phase = 1; dd("calling content handler"); return llcf->content_handler(r); }
static void ngx_http_lua_timer_handler(ngx_event_t *ev) { int n; lua_State *L; ngx_int_t rc; ngx_connection_t *c = NULL; ngx_http_request_t *r = NULL; ngx_http_lua_ctx_t *ctx; ngx_http_cleanup_t *cln; ngx_pool_cleanup_t *pcln; ngx_http_lua_timer_ctx_t tctx; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua ngx.timer expired"); ngx_memcpy(&tctx, ev->data, sizeof(ngx_http_lua_timer_ctx_t)); ngx_free(ev); ev = NULL; lmcf = tctx.lmcf; lmcf->pending_timers--; if (lmcf->running_timers >= lmcf->max_running_timers) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "%i lua_max_running_timers are not enough", lmcf->max_running_timers); goto failed; } c = ngx_http_lua_create_fake_connection(tctx.pool); if (c == NULL) { goto failed; } c->log->handler = ngx_http_lua_log_timer_error; c->log->data = c; c->listening = tctx.listening; c->addr_text = tctx.client_addr_text; r = ngx_http_lua_create_fake_request(c); if (r == NULL) { goto failed; } r->main_conf = tctx.main_conf; r->srv_conf = tctx.srv_conf; r->loc_conf = tctx.loc_conf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); #if defined(nginx_version) && nginx_version >= 1003014 ngx_http_set_connection_log(r->connection, clcf->error_log); #else c->log->file = clcf->error_log->file; if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { c->log->log_level = clcf->error_log->log_level; } #endif dd("lmcf: %p", lmcf); ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { goto failed; } if (tctx.vm_state) { ctx->vm_state = tctx.vm_state; pcln = ngx_pool_cleanup_add(r->pool, 0); if (pcln == NULL) { goto failed; } pcln->handler = ngx_http_lua_cleanup_vm; pcln->data = tctx.vm_state; } ctx->cur_co_ctx = &ctx->entry_co_ctx; L = ngx_http_lua_get_lua_vm(r, ctx); cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { goto failed; } cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = ctx; ctx->cleanup = &cln->handler; ctx->entered_content_phase = 1; ctx->context = NGX_HTTP_LUA_CONTEXT_TIMER; r->read_event_handler = ngx_http_block_reading; ctx->cur_co_ctx->co_ref = tctx.co_ref; ctx->cur_co_ctx->co = tctx.co; ctx->cur_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING; dd("r connection: %p, log %p", r->connection, r->connection->log); /* save the request in coroutine globals table */ ngx_http_lua_set_req(tctx.co, r); lmcf->running_timers++; lua_pushboolean(tctx.co, tctx.premature); n = lua_gettop(tctx.co); if (n > 2) { lua_insert(tctx.co, 2); } #ifdef NGX_LUA_USE_ASSERT ctx->cur_co_ctx->co_top = 1; #endif rc = ngx_http_lua_run_thread(L, r, ctx, n - 1); dd("timer lua run thread: %d", (int) rc); if (rc == NGX_ERROR || rc >= NGX_OK) { /* do nothing */ } else if (rc == NGX_AGAIN) { rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 0); } else if (rc == NGX_DONE) { rc = ngx_http_lua_content_run_posted_threads(L, r, ctx, 1); } else { rc = NGX_OK; } ngx_http_lua_finalize_request(r, rc); return; failed: if (tctx.co_ref && tctx.co) { lua_pushlightuserdata(tctx.co, &ngx_http_lua_coroutines_key); lua_rawget(tctx.co, LUA_REGISTRYINDEX); luaL_unref(tctx.co, -1, tctx.co_ref); lua_settop(tctx.co, 0); } if (tctx.vm_state) { ngx_http_lua_cleanup_vm(tctx.vm_state); } if (c) { ngx_http_lua_close_fake_connection(c); } else if (tctx.pool) { ngx_destroy_pool(tctx.pool); } }
ngx_int_t ngx_http_lua_rewrite_handler(ngx_http_request_t *r) { ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; ngx_http_lua_main_conf_t *lmcf; /* XXX we need to take into account ngx_rewrite's location dump */ if (r->uri_changed) { return NGX_DECLINED; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua rewrite handler, uri \"%V\"", &r->uri); lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); if (!lmcf->postponed_to_rewrite_phase_end) { ngx_http_core_main_conf_t *cmcf; ngx_http_phase_handler_t tmp; ngx_http_phase_handler_t *ph; ngx_http_phase_handler_t *cur_ph; ngx_http_phase_handler_t *last_ph; lmcf->postponed_to_rewrite_phase_end = 1; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); ph = cmcf->phase_engine.handlers; cur_ph = &ph[r->phase_handler]; last_ph = &ph[cur_ph->next - 1]; #if 0 if (cur_ph == last_ph) { dd("XXX our handler is already the last rewrite phase handler"); } #endif if (cur_ph < last_ph) { dd("swaping the contents of cur_ph and last_ph..."); tmp = *cur_ph; memmove(cur_ph, cur_ph + 1, (last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t)); *last_ph = tmp; r->phase_handler--; /* redo the current ph */ return NGX_DECLINED; } } llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->rewrite_handler == NULL) { dd("no rewrite handler found"); return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } dd("entered? %d", (int) ctx->entered_rewrite_phase); if (ctx->entered_rewrite_phase) { dd("rewriteby: calling wev handler"); rc = ctx->resume_handler(r); dd("rewriteby: wev handler returns %d", (int) rc); if (rc == NGX_OK) { return NGX_DECLINED; } return rc; } if (ctx->waiting_more_body) { return NGX_DONE; } if (llcf->force_read_body && !ctx->read_body_done) { r->request_body_in_single_buf = 1; r->request_body_in_persistent_file = 1; r->request_body_in_clean_file = 1; rc = ngx_http_read_client_request_body(r, ngx_http_lua_generic_phase_post_read); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { #if (nginx_version < 1002006) || \ (nginx_version >= 1003000 && nginx_version < 1003009) r->main->count--; #endif return rc; } if (rc == NGX_AGAIN) { ctx->waiting_more_body = 1; return NGX_DONE; } } dd("calling rewrite handler"); return llcf->rewrite_handler(r); }
static ngx_int_t ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; uint8_t old_context; ngx_http_cleanup_t *cln; ngx_http_lua_main_conf_t *lmcf; lua_State *L; ngx_chain_t *out; ngx_buf_tag_t tag; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua body filter for user lua code, uri \"%V\"", &r->uri); if (in == NULL) { return ngx_http_next_body_filter(r, in); } llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->body_filter_handler == NULL) { dd("no body filter handler found"); return ngx_http_next_body_filter(r, in); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } } if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_ERROR; } cln->handler = ngx_http_lua_request_cleanup; cln->data = r; ctx->cleanup = &cln->handler; } old_context = ctx->context; ctx->context = NGX_HTTP_LUA_CONTEXT_BODY_FILTER; dd("calling body filter handler"); rc = llcf->body_filter_handler(r, in); dd("calling body filter handler returned %d", (int) rc); ctx->context = old_context; if (rc != NGX_OK) { return NGX_ERROR; } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); L = lmcf->lua; lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_rawget(L, LUA_GLOBALSINDEX); out = lua_touserdata(L, -1); lua_pop(L, 1); if (in == out) { return ngx_http_next_body_filter(r, in); } /* in != out */ rc = ngx_http_next_body_filter(r, out); if (rc == NGX_ERROR) { return NGX_ERROR; } tag = (ngx_buf_tag_t) &ngx_http_lua_module; #if nginx_version >= 1001004 ngx_chain_update_chains(r->pool, #else ngx_chain_update_chains( #endif &ctx->free_bufs, &ctx->busy_bufs, &out, tag); return rc; }
static ngx_int_t ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_ctx_t *ctx; ngx_int_t rc; uint16_t old_context; ngx_http_cleanup_t *cln; lua_State *L; ngx_chain_t *out; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua body filter for user lua code, uri \"%V\"", &r->uri); if (in == NULL) { return ngx_http_next_body_filter(r, in); } llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->body_filter_handler == NULL) { dd("no body filter handler found"); return ngx_http_next_body_filter(r, in); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); dd("ctx = %p", ctx); if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { return NGX_ERROR; } } if (ctx->seen_last_in_filter) { for (/* void */; in; in = in->next) { dd("mark the buf as consumed: %d", (int) ngx_buf_size(in->buf)); in->buf->pos = in->buf->last; in->buf->file_pos = in->buf->file_last; } return NGX_OK; } if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_ERROR; } cln->handler = ngx_http_lua_request_cleanup_handler; cln->data = ctx; ctx->cleanup = &cln->handler; } old_context = ctx->context; ctx->context = NGX_HTTP_LUA_CONTEXT_BODY_FILTER; dd("calling body filter handler"); rc = llcf->body_filter_handler(r, in); dd("calling body filter handler returned %d", (int) rc); ctx->context = old_context; if (rc != NGX_OK) { return NGX_ERROR; } L = ngx_http_lua_get_lua_vm(r, ctx); lua_getglobal(L, ngx_http_lua_chain_key); out = lua_touserdata(L, -1); lua_pop(L, 1); if (in == out) { return ngx_http_next_body_filter(r, in); } if (out == NULL) { /* do not forward NULL to the next filters because the input is * not NULL */ return NGX_OK; } /* in != out */ rc = ngx_http_next_body_filter(r, out); if (rc == NGX_ERROR) { return NGX_ERROR; } #if nginx_version >= 1001004 ngx_chain_update_chains(r->pool, #else ngx_chain_update_chains( #endif &ctx->free_bufs, &ctx->busy_bufs, &out, (ngx_buf_tag_t) &ngx_http_lua_module); return rc; }
ngx_int_t ngx_http_lua_init_worker(ngx_cycle_t *cycle) { char *rv; void *cur, *prev; ngx_uint_t i; ngx_conf_t conf; ngx_connection_t *c = NULL; ngx_http_module_t *module; ngx_http_request_t *r = NULL; ngx_http_lua_ctx_t *ctx; ngx_http_conf_ctx_t *conf_ctx, http_ctx; ngx_http_lua_loc_conf_t *llcf; ngx_http_lua_main_conf_t *lmcf; ngx_http_core_loc_conf_t *clcf; lmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_lua_module); if (lmcf == NULL || lmcf->init_worker_handler == NULL || lmcf->lua == NULL) { return NGX_OK; } conf_ctx = ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]); http_ctx.main_conf = conf_ctx->main_conf; ngx_memzero(&conf, sizeof(ngx_conf_t)); conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, cycle->log); if (conf.temp_pool == NULL) { return NGX_ERROR; } conf.ctx = &http_ctx; conf.cycle = cycle; conf.pool = cycle->pool; conf.log = cycle->log; http_ctx.loc_conf = ngx_pcalloc(conf.pool, sizeof(void *) * ngx_http_max_module); if (http_ctx.loc_conf == NULL) { return NGX_ERROR; } http_ctx.srv_conf = ngx_pcalloc(conf.pool, sizeof(void *) * ngx_http_max_module); if (http_ctx.srv_conf == NULL) { return NGX_ERROR; } for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_HTTP_MODULE) { continue; } module = ngx_modules[i]->ctx; if (module->create_srv_conf) { cur = module->create_srv_conf(&conf); if (cur == NULL) { return NGX_ERROR; } if (module->merge_srv_conf) { prev = module->create_srv_conf(&conf); if (prev == NULL) { return NGX_ERROR; } rv = module->merge_srv_conf(&conf, prev, cur); if (rv != NGX_CONF_OK) { goto failed; } } http_ctx.srv_conf[ngx_modules[i]->ctx_index] = cur; } if (module->create_loc_conf) { cur = module->create_loc_conf(&conf); if (cur == NULL) { return NGX_ERROR; } if (module->merge_loc_conf) { prev = module->create_loc_conf(&conf); if (prev == NULL) { return NGX_ERROR; } rv = module->merge_loc_conf(&conf, prev, cur); if (rv != NGX_CONF_OK) { goto failed; } } http_ctx.loc_conf[ngx_modules[i]->ctx_index] = cur; } } ngx_destroy_pool(conf.temp_pool); conf.temp_pool = NULL; c = ngx_http_lua_create_fake_connection(); if (c == NULL) { goto failed; } c->log->handler = ngx_http_lua_log_init_worker_error; r = ngx_http_lua_create_fake_request(c); if (r == NULL) { goto failed; } r->main_conf = http_ctx.main_conf; r->srv_conf = http_ctx.srv_conf; r->loc_conf = http_ctx.loc_conf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); c->log->file = clcf->error_log->file; if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { c->log->log_level = clcf->error_log->log_level; } ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { goto failed; } ctx->context = NGX_HTTP_LUA_CONTEXT_INIT_WORKER; ctx->cur_co_ctx = NULL; r->read_event_handler = ngx_http_block_reading; llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); llcf->log_socket_errors = 0; ngx_http_lua_set_req(lmcf->lua, r); (void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua); ngx_destroy_pool(r->pool); ngx_destroy_pool(c->pool); return NGX_OK; failed: if (conf.temp_pool) { ngx_destroy_pool(conf.temp_pool); } if (r && r->pool) { ngx_destroy_pool(r->pool); } if (c) { ngx_http_lua_close_fake_connection(c); } return NGX_ERROR; }