blob: 4a3ab98aa6461e4ca0df39ca8ffd7670c104ff6c [file] [log] [blame] [raw]
/*
* Copyright (C) Xiaozhe Wang (chaoslawful)
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_lua_contentby.h"
#include "ngx_http_lua_util.h"
#include "ngx_http_lua_exception.h"
#include "ngx_http_lua_cache.h"
#include "ngx_http_lua_probe.h"
static void ngx_http_lua_content_phase_post_read(ngx_http_request_t *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 = ctx;
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;
}
void
ngx_http_lua_content_wev_handler(ngx_http_request_t *r)
{
ngx_http_lua_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
if (ctx == NULL) {
return;
}
(void) ctx->resume_handler(r);
}
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);
}
/* post read callback for the content phase */
static void
ngx_http_lua_content_phase_post_read(ngx_http_request_t *r)
{
ngx_http_lua_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
ctx->read_body_done = 1;
if (ctx->waiting_more_body) {
ctx->waiting_more_body = 0;
ngx_http_lua_finalize_request(r, ngx_http_lua_content_handler(r));
} else {
r->main->count--;
}
}
ngx_int_t
ngx_http_lua_content_handler_file(ngx_http_request_t *r)
{
lua_State *L;
ngx_int_t rc;
u_char *script_path;
ngx_http_lua_loc_conf_t *llcf;
ngx_str_t eval_src;
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
if (ngx_http_complex_value(r, &llcf->content_src, &eval_src) != NGX_OK) {
return NGX_ERROR;
}
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
eval_src.len);
if (script_path == NULL) {
return NGX_ERROR;
}
L = ngx_http_lua_get_lua_vm(r, NULL);
/* load Lua script file (w/ cache) sp = 1 */
rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->content_src_key);
if (rc != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
/* make sure we have a valid code chunk */
assert(lua_isfunction(L, -1));
return ngx_http_lua_content_by_chunk(L, r);
}
ngx_int_t
ngx_http_lua_content_handler_inline(ngx_http_request_t *r)
{
lua_State *L;
ngx_int_t rc;
ngx_http_lua_loc_conf_t *llcf;
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
L = ngx_http_lua_get_lua_vm(r, NULL);
/* load Lua inline script (w/ cache) sp = 1 */
rc = ngx_http_lua_cache_loadbuffer(L, llcf->content_src.value.data,
llcf->content_src.value.len,
llcf->content_src_key,
"content_by_lua");
if (rc != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
return ngx_http_lua_content_by_chunk(L, r);
}
ngx_int_t
ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r,
ngx_http_lua_ctx_t *ctx, int n)
{
ngx_int_t rc;
ngx_http_lua_posted_thread_t *pt;
dd("run posted threads: %p", ctx->posted_threads);
for ( ;; ) {
pt = ctx->posted_threads;
if (pt == NULL) {
goto done;
}
ctx->posted_threads = pt->next;
ngx_http_lua_probe_run_posted_thread(r, pt->co_ctx->co,
(int) pt->co_ctx->co_status);
dd("posted thread status: %d", pt->co_ctx->co_status);
if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) {
continue;
}
ctx->cur_co_ctx = pt->co_ctx;
rc = ngx_http_lua_run_thread(L, r, ctx, 0);
if (rc == NGX_AGAIN) {
continue;
}
if (rc == NGX_DONE) {
n++;
continue;
}
if (rc == NGX_OK) {
while (n > 0) {
ngx_http_lua_finalize_request(r, NGX_DONE);
n--;
}
return NGX_OK;
}
/* rc == NGX_ERROR || rc > NGX_OK */
return rc;
}
done:
if (n == 1) {
return NGX_DONE;
}
if (n == 0) {
r->main->count++;
return NGX_DONE;
}
/* n > 1 */
do {
ngx_http_lua_finalize_request(r, NGX_DONE);
} while (--n > 1);
return NGX_DONE;
}
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */