summaryrefslogtreecommitdiff
path: root/ngx_stream_lua-0.0.16/src/ngx_stream_lua_output.c
diff options
context:
space:
mode:
authorkaiwu <kaiwu2004@gmail.com>2025-03-01 12:42:23 +0800
committerkaiwu <kaiwu2004@gmail.com>2025-03-01 12:42:23 +0800
commit3f33461e4948bf05e60bdff35ec6c57a649c7860 (patch)
tree284c2ba95a41536ae1bff6bea710db0709a64739 /ngx_stream_lua-0.0.16/src/ngx_stream_lua_output.c
downloadopenresty-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.c739
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: */