diff options
author | kaiwu <kaiwu2004@gmail.com> | 2025-03-01 12:42:23 +0800 |
---|---|---|
committer | kaiwu <kaiwu2004@gmail.com> | 2025-03-01 12:42:23 +0800 |
commit | 3f33461e4948bf05e60bdff35ec6c57a649c7860 (patch) | |
tree | 284c2ba95a41536ae1bff6bea710db0709a64739 /ngx_stream_lua-0.0.16/src/ngx_stream_lua_output.c | |
download | openresty-3f33461e4948bf05e60bdff35ec6c57a649c7860.tar.gz openresty-3f33461e4948bf05e60bdff35ec6c57a649c7860.zip |
openresty bundle
Diffstat (limited to 'ngx_stream_lua-0.0.16/src/ngx_stream_lua_output.c')
-rw-r--r-- | ngx_stream_lua-0.0.16/src/ngx_stream_lua_output.c | 739 |
1 files changed, 739 insertions, 0 deletions
diff --git a/ngx_stream_lua-0.0.16/src/ngx_stream_lua_output.c b/ngx_stream_lua-0.0.16/src/ngx_stream_lua_output.c new file mode 100644 index 0000000..cfb33cb --- /dev/null +++ b/ngx_stream_lua-0.0.16/src/ngx_stream_lua_output.c @@ -0,0 +1,739 @@ + +/* + * !!! DO NOT EDIT DIRECTLY !!! + * This file was automatically generated from the following template: + * + * src/subsys/ngx_subsys_lua_output.c.tt2 + */ + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_stream_lua_output.h" +#include "ngx_stream_lua_util.h" +#include "ngx_stream_lua_contentby.h" +#include <math.h> + + +static int ngx_stream_lua_ngx_say(lua_State *L); +static int ngx_stream_lua_ngx_print(lua_State *L); +static int ngx_stream_lua_ngx_flush(lua_State *L); +static int ngx_stream_lua_ngx_eof(lua_State *L); + + +static int ngx_stream_lua_ngx_echo(lua_State *L, unsigned newline); +static void ngx_stream_lua_flush_cleanup(void *data); + + +static int +ngx_stream_lua_ngx_print(lua_State *L) +{ + dd("calling lua print"); + return ngx_stream_lua_ngx_echo(L, 0); +} + + +static int +ngx_stream_lua_ngx_say(lua_State *L) +{ + dd("calling"); + return ngx_stream_lua_ngx_echo(L, 1); +} + + +static int +ngx_stream_lua_ngx_echo(lua_State *L, unsigned newline) +{ + ngx_stream_lua_request_t *r; + ngx_stream_lua_ctx_t *ctx; + const char *p; + size_t len; + size_t size; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_int_t rc; + int i; + int nargs; + int type; + const char *msg; + + r = ngx_stream_lua_get_req(L); + if (r == NULL) { + return luaL_error(L, "no request object found"); + } + + ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module); + + if (ctx == NULL) { + return luaL_error(L, "no request ctx found"); + } + + if (r->connection->type == SOCK_DGRAM) { + return luaL_error(L, "API disabled in the current context"); + } + + ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT + | NGX_STREAM_LUA_CONTEXT_PREREAD); + + + if (ctx->eof) { + lua_pushnil(L); + lua_pushliteral(L, "seen eof"); + return 2; + } + + nargs = lua_gettop(L); + size = 0; + + for (i = 1; i <= nargs; i++) { + + type = lua_type(L, i); + + switch (type) { + case LUA_TNUMBER: + case LUA_TSTRING: + + lua_tolstring(L, i, &len); + size += len; + break; + + case LUA_TNIL: + + size += sizeof("nil") - 1; + break; + + case LUA_TBOOLEAN: + + if (lua_toboolean(L, i)) { + size += sizeof("true") - 1; + + } else { + size += sizeof("false") - 1; + } + + break; + + case LUA_TTABLE: + + size += ngx_stream_lua_calc_strlen_in_table(L, i, i, + 0 /* strict */); + break; + + case LUA_TLIGHTUSERDATA: + + dd("userdata: %p", lua_touserdata(L, i)); + + if (lua_touserdata(L, i) == NULL) { + size += sizeof("null") - 1; + break; + } + + continue; + + default: + + msg = lua_pushfstring(L, "string, number, boolean, nil, " + "ngx.null, or array table expected, " + "but got %s", lua_typename(L, type)); + + return luaL_argerror(L, i, msg); + } + } + + if (newline) { + size += sizeof("\n") - 1; + } + + if (size == 0) { + + lua_pushinteger(L, 1); + return 1; + } + + ctx->seen_body_data = 1; + + cl = ngx_stream_lua_chain_get_free_buf(r->connection->log, r->pool, + &ctx->free_bufs, size); + + if (cl == NULL) { + return luaL_error(L, "no memory"); + } + + b = cl->buf; + + for (i = 1; i <= nargs; i++) { + type = lua_type(L, i); + switch (type) { + case LUA_TNUMBER: + case LUA_TSTRING: + p = lua_tolstring(L, i, &len); + b->last = ngx_copy(b->last, (u_char *) p, len); + break; + + case LUA_TNIL: + *b->last++ = 'n'; + *b->last++ = 'i'; + *b->last++ = 'l'; + break; + + case LUA_TBOOLEAN: + if (lua_toboolean(L, i)) { + *b->last++ = 't'; + *b->last++ = 'r'; + *b->last++ = 'u'; + *b->last++ = 'e'; + + } else { + *b->last++ = 'f'; + *b->last++ = 'a'; + *b->last++ = 'l'; + *b->last++ = 's'; + *b->last++ = 'e'; + } + + break; + + case LUA_TTABLE: + b->last = ngx_stream_lua_copy_str_in_table(L, i, b->last); + break; + + case LUA_TLIGHTUSERDATA: + *b->last++ = 'n'; + *b->last++ = 'u'; + *b->last++ = 'l'; + *b->last++ = 'l'; + break; + + default: + return luaL_error(L, "impossible to reach here"); + } + } + + if (newline) { + *b->last++ = '\n'; + } + +#if 0 + if (b->last != b->end) { + return luaL_error(L, "buffer error: %p != %p", b->last, b->end); + } +#endif + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, + newline ? "lua say response" : "lua print response"); + + rc = ngx_stream_lua_send_chain_link(r, ctx, cl); + + if (rc == NGX_ERROR) { + lua_pushnil(L); + lua_pushliteral(L, "nginx output filter error"); + return 2; + } + + dd("downstream write: %d, buf len: %d", (int) rc, + (int) (b->last - b->pos)); + + lua_pushinteger(L, 1); + return 1; +} + + +size_t +ngx_stream_lua_calc_strlen_in_table(lua_State *L, int index, int arg_i, + unsigned strict) +{ + double key; + int max; + int i; + int type; + size_t size; + size_t len; + const char *msg; + + if (index < 0) { + index = lua_gettop(L) + index + 1; + } + + dd("table index: %d", index); + + max = 0; + + lua_pushnil(L); /* stack: table key */ + while (lua_next(L, index) != 0) { /* stack: table key value */ + dd("key type: %s", luaL_typename(L, -2)); + + if (lua_type(L, -2) == LUA_TNUMBER) { + + key = lua_tonumber(L, -2); + + dd("key value: %d", (int) key); + + if (floor(key) == key && key >= 1) { + if (key > max) { + max = (int) key; + } + + lua_pop(L, 1); /* stack: table key */ + continue; + } + } + + /* not an array (non positive integer key) */ + lua_pop(L, 2); /* stack: table */ + + luaL_argerror(L, arg_i, "non-array table found"); + return 0; + } + + size = 0; + + for (i = 1; i <= max; i++) { + lua_rawgeti(L, index, i); /* stack: table value */ + type = lua_type(L, -1); + + switch (type) { + case LUA_TNUMBER: + case LUA_TSTRING: + + lua_tolstring(L, -1, &len); + size += len; + break; + + case LUA_TNIL: + + if (strict) { + goto bad_type; + } + + size += sizeof("nil") - 1; + break; + + case LUA_TBOOLEAN: + + if (strict) { + goto bad_type; + } + + if (lua_toboolean(L, -1)) { + size += sizeof("true") - 1; + + } else { + size += sizeof("false") - 1; + } + + break; + + case LUA_TTABLE: + + size += ngx_stream_lua_calc_strlen_in_table(L, -1, arg_i, + strict); + break; + + case LUA_TLIGHTUSERDATA: + + if (strict) { + goto bad_type; + } + + if (lua_touserdata(L, -1) == NULL) { + size += sizeof("null") - 1; + break; + } + + continue; + + default: + +bad_type: + + msg = lua_pushfstring(L, "bad data type %s found", + lua_typename(L, type)); + return luaL_argerror(L, arg_i, msg); + } + + lua_pop(L, 1); /* stack: table */ + } + + return size; +} + + +u_char * +ngx_stream_lua_copy_str_in_table(lua_State *L, int index, u_char *dst) +{ + double key; + int max; + int i; + int type; + size_t len; + u_char *p; + + if (index < 0) { + index = lua_gettop(L) + index + 1; + } + + max = 0; + + lua_pushnil(L); /* stack: table key */ + while (lua_next(L, index) != 0) { /* stack: table key value */ + key = lua_tonumber(L, -2); + if (key > max) { + max = (int) key; + } + + lua_pop(L, 1); /* stack: table key */ + } + + for (i = 1; i <= max; i++) { + lua_rawgeti(L, index, i); /* stack: table value */ + type = lua_type(L, -1); + switch (type) { + case LUA_TNUMBER: + case LUA_TSTRING: + p = (u_char *) lua_tolstring(L, -1, &len); + dst = ngx_copy(dst, p, len); + break; + + case LUA_TNIL: + *dst++ = 'n'; + *dst++ = 'i'; + *dst++ = 'l'; + break; + + case LUA_TBOOLEAN: + if (lua_toboolean(L, -1)) { + *dst++ = 't'; + *dst++ = 'r'; + *dst++ = 'u'; + *dst++ = 'e'; + + } else { + *dst++ = 'f'; + *dst++ = 'a'; + *dst++ = 'l'; + *dst++ = 's'; + *dst++ = 'e'; + } + + break; + + case LUA_TTABLE: + dst = ngx_stream_lua_copy_str_in_table(L, -1, dst); + break; + + case LUA_TLIGHTUSERDATA: + + *dst++ = 'n'; + *dst++ = 'u'; + *dst++ = 'l'; + *dst++ = 'l'; + break; + + default: + luaL_error(L, "impossible to reach here"); + return NULL; + } + + lua_pop(L, 1); /* stack: table */ + } + + return dst; +} + + +/** + * Force flush out response content + * */ +static int +ngx_stream_lua_ngx_flush(lua_State *L) +{ + ngx_stream_lua_request_t *r; + ngx_stream_lua_ctx_t *ctx; + ngx_chain_t *cl; + ngx_int_t rc; + int n; + unsigned wait = 0; + ngx_event_t *wev; + + ngx_stream_lua_srv_conf_t *cllscf; + + ngx_stream_lua_co_ctx_t *coctx; + + n = lua_gettop(L); + if (n > 1) { + return luaL_error(L, "attempt to pass %d arguments, but accepted 0 " + "or 1", n); + } + + r = ngx_stream_lua_get_req(L); + + if (n == 1) { + luaL_checktype(L, 1, LUA_TBOOLEAN); + wait = lua_toboolean(L, 1); + } + + ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no request ctx found"); + } + + if (r->connection->type == SOCK_DGRAM) { + return luaL_error(L, "API disabled in the current context"); + } + + ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT + | NGX_STREAM_LUA_CONTEXT_PREREAD); + + + coctx = ctx->cur_co_ctx; + if (coctx == NULL) { + return luaL_error(L, "no co ctx found"); + } + + + if (ctx->eof) { + lua_pushnil(L); + lua_pushliteral(L, "seen eof"); + return 2; + } + + + cl = ngx_stream_lua_get_flush_chain(r, ctx); + if (cl == NULL) { + return luaL_error(L, "no memory"); + } + + rc = ngx_stream_lua_send_chain_link(r, ctx, cl); + + dd("send chain: %d", (int) rc); + + if (rc == NGX_ERROR) { + lua_pushnil(L); + lua_pushliteral(L, "nginx output filter error"); + return 2; + } + + dd("wait:%d, rc:%d, buffered:0x%x", wait, (int) rc, + r->connection->buffered); + + wev = r->connection->write; + + if (wait && (r->connection->buffered || wev->delayed)) + { + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, + "lua flush requires waiting: buffered 0x%uxd, " + "delayed:%d", (unsigned) r->connection->buffered, + wev->delayed); + + coctx->flushing = 1; + ctx->flushing_coros++; + + if (ctx->entered_content_phase) { + /* mimic ngx_http_set_write_handler */ + r->write_event_handler = ngx_stream_lua_content_wev_handler; + + } else { + r->write_event_handler = ngx_stream_lua_core_run_phases; + } + + cllscf = ngx_stream_lua_get_module_srv_conf(r, ngx_stream_lua_module); + + if (!wev->delayed) { + ngx_add_timer(wev, cllscf->send_timeout); + } + + + if (ngx_handle_write_event(wev, cllscf->send_lowat) != NGX_OK) { + if (wev->timer_set) { + wev->delayed = 0; + ngx_del_timer(wev); + } + + lua_pushnil(L); + lua_pushliteral(L, "connection broken"); + return 2; + } + + ngx_stream_lua_cleanup_pending_operation(ctx->cur_co_ctx); + coctx->cleanup = ngx_stream_lua_flush_cleanup; + coctx->data = r; + + return lua_yield(L, 0); + } + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, + "lua flush asynchronously"); + + lua_pushinteger(L, 1); + return 1; +} + + +/** + * Send last_buf, terminate output stream + * */ +static int +ngx_stream_lua_ngx_eof(lua_State *L) +{ + ngx_stream_lua_request_t *r; + ngx_stream_lua_ctx_t *ctx; + ngx_int_t rc; + + r = ngx_stream_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_stream_lua_get_module_ctx(r, ngx_stream_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + + + if (ctx->eof) { + lua_pushnil(L); + lua_pushliteral(L, "seen eof"); + return 2; + } + + if (r->connection->type == SOCK_DGRAM) { + return luaL_error(L, "API disabled in the current context"); + } + + ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT + | NGX_STREAM_LUA_CONTEXT_PREREAD); + + ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, + "lua send eof"); + + rc = ngx_stream_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */); + + dd("send chain: %d", (int) rc); + + if (rc == NGX_ERROR) { + lua_pushnil(L); + lua_pushliteral(L, "nginx output filter error"); + return 2; + } + + lua_pushinteger(L, 1); + return 1; +} + + +void +ngx_stream_lua_inject_output_api(lua_State *L) +{ + + lua_pushcfunction(L, ngx_stream_lua_ngx_print); + lua_setfield(L, -2, "print"); + + lua_pushcfunction(L, ngx_stream_lua_ngx_say); + lua_setfield(L, -2, "say"); + + lua_pushcfunction(L, ngx_stream_lua_ngx_flush); + lua_setfield(L, -2, "flush"); + + lua_pushcfunction(L, ngx_stream_lua_ngx_eof); + lua_setfield(L, -2, "eof"); +} + + + + +ngx_int_t +ngx_stream_lua_flush_resume_helper(ngx_stream_lua_request_t *r, + ngx_stream_lua_ctx_t *ctx) +{ + int n; + lua_State *vm; + ngx_int_t rc; + ngx_uint_t nreqs; + ngx_connection_t *c; + + c = r->connection; + + ctx->cur_co_ctx->cleanup = NULL; + + /* push the return values */ + + if (c->timedout) { + lua_pushnil(ctx->cur_co_ctx->co); + lua_pushliteral(ctx->cur_co_ctx->co, "timeout"); + n = 2; + + } else if (c->error) { + lua_pushnil(ctx->cur_co_ctx->co); + lua_pushliteral(ctx->cur_co_ctx->co, "client aborted"); + n = 2; + + } else { + lua_pushinteger(ctx->cur_co_ctx->co, 1); + n = 1; + } + + vm = ngx_stream_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + + rc = ngx_stream_lua_run_thread(vm, r, ctx, n); + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0, + "lua run thread returned %d", rc); + + if (rc == NGX_AGAIN) { + return ngx_stream_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + if (rc == NGX_DONE) { + ngx_stream_lua_finalize_request(r, NGX_DONE); + return ngx_stream_lua_run_posted_threads(c, vm, r, ctx, nreqs); + } + + /* rc == NGX_ERROR || rc >= NGX_OK */ + + if (ctx->entered_content_phase) { + ngx_stream_lua_finalize_request(r, rc); + return NGX_DONE; + } + + return rc; +} + + +static void +ngx_stream_lua_flush_cleanup(void *data) +{ + ngx_stream_lua_request_t *r; + ngx_event_t *wev; + ngx_stream_lua_ctx_t *ctx; + ngx_stream_lua_co_ctx_t *coctx = data; + + coctx->flushing = 0; + + r = coctx->data; + if (r == NULL) { + return; + } + + wev = r->connection->write; + + if (wev && wev->timer_set) { + ngx_del_timer(wev); + } + + ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module); + if (ctx == NULL) { + return; + } + + ctx->flushing_coros--; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ |