int ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { int type; int idx; int found; u_char *data; size_t size; unsigned last; unsigned flush = 0; ngx_buf_t *b; ngx_chain_t *cl; ngx_chain_t *in; idx = luaL_checkint(L, 2); dd("index: %d", idx); if (idx != 1 && idx != 2) { return luaL_error(L, "bad index: %d", idx); } if (idx == 2) { /* overwriting the eof flag */ last = lua_toboolean(L, 3); lua_getglobal(L, ngx_http_lua_chain_key); in = lua_touserdata(L, -1); lua_pop(L, 1); if (last) { ctx->seen_last_in_filter = 1; /* the "in" chain cannot be NULL and we set the "last_buf" or * "last_in_chain" flag in the last buf of "in" */ for (cl = in; cl; cl = cl->next) { if (cl->next == NULL) { if (r == r->main) { cl->buf->last_buf = 1; } else { cl->buf->last_in_chain = 1; } break; } } } else { /* last == 0 */ found = 0; for (cl = in; cl; cl = cl->next) { b = cl->buf; if (b->last_buf) { b->last_buf = 0; found = 1; } if (b->last_in_chain) { b->last_in_chain = 0; found = 1; } if (found && b->last == b->pos && !ngx_buf_in_memory(b)) { /* make it a special sync buf to make * ngx_http_write_filter_module happy. */ b->sync = 1; } } ctx->seen_last_in_filter = 0; } return 0; } /* idx == 1, overwriting the chunk data */ type = lua_type(L, 3); switch (type) { case LUA_TSTRING: case LUA_TNUMBER: data = (u_char *) lua_tolstring(L, 3, &size); break; case LUA_TNIL: /* discard the buffers */ lua_getglobal(L, ngx_http_lua_chain_key); /* key val */ in = lua_touserdata(L, -1); lua_pop(L, 1); last = 0; for (cl = in; cl; cl = cl->next) { b = cl->buf; if (b->flush) { flush = 1; } if (b->last_in_chain || b->last_buf) { last = 1; } dd("mark the buf as consumed: %d", (int) ngx_buf_size(b)); b->pos = b->last; } /* cl == NULL */ goto done; case LUA_TTABLE: size = ngx_http_lua_calc_strlen_in_table(L, 3 /* index */, 3 /* arg */, 1 /* strict */); data = NULL; break; default: return luaL_error(L, "bad chunk data type: %s", lua_typename(L, type)); } lua_getglobal(L, ngx_http_lua_chain_key); in = lua_touserdata(L, -1); lua_pop(L, 1); last = 0; for (cl = in; cl; cl = cl->next) { b = cl->buf; if (b->flush) { flush = 1; } if (b->last_buf || b->last_in_chain) { last = 1; } dd("mark the buf as consumed: %d", (int) ngx_buf_size(cl->buf)); cl->buf->pos = cl->buf->last; } /* cl == NULL */ if (size == 0) { goto done; } cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, &ctx->free_bufs, size); if (cl == NULL) { return luaL_error(L, "no memory"); } if (type == LUA_TTABLE) { cl->buf->last = ngx_http_lua_copy_str_in_table(L, 3, cl->buf->last); } else { cl->buf->last = ngx_copy(cl->buf->pos, data, size); } done: if (last || flush) { if (cl == NULL) { cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool, &ctx->free_bufs, 0); if (cl == NULL) { return luaL_error(L, "no memory"); } } if (last) { ctx->seen_last_in_filter = 1; if (r == r->main) { cl->buf->last_buf = 1; } else { cl->buf->last_in_chain = 1; } } if (flush) { cl->buf->flush = 1; } } lua_pushlightuserdata(L, cl); lua_setglobal(L, ngx_http_lua_chain_key); return 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)); } lua_pushlightuserdata(L, &ngx_http_lua_request_key); lua_rawget(L, LUA_GLOBALSINDEX); r = lua_touserdata(L, -1); lua_pop(L, 1); 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->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; }
int ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { int type; int idx; u_char *data; size_t size; unsigned last; ngx_chain_t *cl; ngx_chain_t *in; ngx_buf_tag_t tag; idx = luaL_checkint(L, 2); dd("index: %d", idx); if (idx != 1 && idx != 2) { return luaL_error(L, "bad index: %d", idx); } if (idx == 2) { /* overwriting the eof flag */ last = lua_toboolean(L, 3); lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_rawget(L, LUA_GLOBALSINDEX); in = lua_touserdata(L, -1); if (last) { if (in) { for (cl = in; cl; cl = cl->next) { if (cl->next == NULL) { cl->buf->last_buf = 1; break; } } } else { tag = (ngx_buf_tag_t) &ngx_http_lua_module; cl = ngx_http_lua_chains_get_free_buf(r->connection->log, r->pool, &ctx->free_bufs, 0, tag); if (cl == NULL) { return luaL_error(L, "out of memory"); } cl->buf->last_buf = 1; lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_pushlightuserdata(L, cl); lua_rawset(L, LUA_GLOBALSINDEX); } } else { /* last == 0 */ if (in) { for (size = 0, cl = in; cl; cl = cl->next) { if (cl->buf->last_buf) { cl->buf->last_buf = 0; } size += cl->buf->last - cl->buf->pos; } if (size == 0) { lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_pushlightuserdata(L, NULL); lua_rawset(L, LUA_GLOBALSINDEX); } } } return 0; } /* idx == 1, overwriting the chunk data */ type = lua_type(L, 3); switch (type) { case LUA_TSTRING: case LUA_TNUMBER: data = (u_char *) lua_tolstring(L, 3, &size); break; case LUA_TNIL: /* discard the buffers */ lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); /* key */ lua_pushvalue(L, -1); /* key key */ lua_rawget(L, LUA_GLOBALSINDEX); /* key val */ in = lua_touserdata(L, -1); lua_pop(L, 1); /* key */ for (cl = in; cl; cl = cl->next) { dd("mark the buf as consumed: %d", (int) ngx_buf_size(cl->buf)); cl->buf->pos = cl->buf->last; } lua_pushlightuserdata(L, NULL); /* key val */ lua_rawset(L, LUA_GLOBALSINDEX); return 0; case LUA_TTABLE: size = ngx_http_lua_calc_strlen_in_table(L, 3 /* index */, 3 /* arg */, 1 /* strict */); data = NULL; break; default: return luaL_error(L, "bad chunk data type: %s", lua_typename(L, type)); } lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_rawget(L, LUA_GLOBALSINDEX); in = lua_touserdata(L, -1); lua_pop(L, 1); last = 0; for (cl = in; cl; cl = cl->next) { if (cl->buf->last_buf) { last = 1; } dd("mark the buf as consumed: %d", (int) ngx_buf_size(cl->buf)); cl->buf->pos = cl->buf->last; } if (size == 0) { if (last) { if (in) { in->buf->last_buf = 1; } else { tag = (ngx_buf_tag_t) &ngx_http_lua_module; cl = ngx_http_lua_chains_get_free_buf(r->connection->log, r->pool, &ctx->free_bufs, 0, tag); if (cl == NULL) { return luaL_error(L, "out of memory"); } cl->buf->last_buf = 1; lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_pushlightuserdata(L, cl); lua_rawset(L, LUA_GLOBALSINDEX); } } return 0; } tag = (ngx_buf_tag_t) &ngx_http_lua_module; cl = ngx_http_lua_chains_get_free_buf(r->connection->log, r->pool, &ctx->free_bufs, size, tag); if (cl == NULL) { return luaL_error(L, "out of memory"); } if (type == LUA_TTABLE) { cl->buf->last = ngx_http_lua_copy_str_in_table(L, 3, cl->buf->last); } else { cl->buf->last = ngx_copy(cl->buf->pos, data, size); } cl->buf->last_buf = last; lua_pushlightuserdata(L, &ngx_http_lua_body_filter_chain_key); lua_pushlightuserdata(L, cl); lua_rawset(L, LUA_GLOBALSINDEX); return 0; }
static int ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) { ngx_http_request_t *r; ngx_http_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_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 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); if (ctx->acquired_raw_req_socket) { lua_pushnil(L); lua_pushliteral(L, "raw request socket acquired"); return 2; } if (r->header_only) { lua_pushnil(L); lua_pushliteral(L, "header only"); return 2; } 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_http_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) { /* do nothing for empty strings */ lua_pushinteger(L, 1); return 1; } cl = ngx_http_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_http_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_HTTP, r->connection->log, 0, newline ? "lua say response" : "lua print response"); rc = ngx_http_lua_send_chain_link(r, ctx, cl); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { 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; }
u_char * ngx_http_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_http_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; }
static int ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) { ngx_http_request_t *r; ngx_http_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; ngx_buf_tag_t tag; lua_getglobal(L, GLOBALS_SYMBOL_REQUEST); r = lua_touserdata(L, -1); lua_pop(L, 1); 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 request ctx found"); } if ((r->method & NGX_HTTP_HEAD) || r->header_only) { return 0; } if (ctx->eof) { return luaL_error(L, "seen eof already"); } 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_http_lua_calc_strlen_in_table(L, i, 0); 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) { /* do nothing for empty strings */ return 0; } tag = (ngx_buf_tag_t) &ngx_http_lua_module; cl = ngx_http_lua_chains_get_free_buf(r->connection->log, r->pool, &ctx->free_bufs, size, tag); if (cl == NULL) { return luaL_error(L, "out of 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_http_lua_copy_str_in_table(L, 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_HTTP, r->connection->log, 0, newline ? "lua say response" : "lua print response"); rc = ngx_http_lua_send_chain_link(r, ctx, cl); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return luaL_error(L, "failed to send data through the output filters"); } dd("downstream write: %d, buf len: %d", (int) rc, (int) (b->last - b->pos)); if (!ctx->out) { #if nginx_version >= 1001004 ngx_chain_update_chains(r->pool, #else ngx_chain_update_chains( #endif &ctx->free_bufs, &ctx->busy_bufs, &cl, tag); dd("out lua buf tag: %p, buffered: %x, busy bufs: %p", &ngx_http_lua_module, (int) r->connection->buffered, ctx->busy_bufs); }
static int ngx_http_lua_ngx_echo(lua_State *L, unsigned newline) { ngx_http_request_t *r; ngx_http_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; lua_getglobal(L, GLOBALS_SYMBOL_REQUEST); r = lua_touserdata(L, -1); lua_pop(L, 1); 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 request ctx found"); } if ((r->method & NGX_HTTP_HEAD) || r->header_only) { return 0; } if (ctx->eof) { return luaL_error(L, "seen eof already"); } 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_http_lua_calc_strlen_in_table(L, i); break; default: msg = lua_pushfstring(L, "string, number, boolean, nil, " "or array table expected, got %s", lua_typename(L, type)); return luaL_argerror(L, i, msg); } } if (newline) { size += sizeof("\n") - 1; } if (size == 0) { /* do nothing for empty strings */ return 0; } b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { return luaL_error(L, "out of memory"); } 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_http_lua_copy_str_in_table(L, b->last); break; default: return luaL_error(L, "impossible to reach here"); } } if (newline) { *b->last++ = '\n'; } if (b->last != b->end) { return luaL_error(L, "buffer error: %p != %p", b->last, b->end); } cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { return luaL_error(L, "out of memory"); } cl->next = NULL; cl->buf = b; rc = ngx_http_lua_send_chain_link(r, ctx, cl); if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { return luaL_error(L, "failed to send data through the output filters"); } return 0; }
int ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) { int type; int idx; int found; u_char *data; size_t size; unsigned last; ngx_chain_t *cl; ngx_chain_t *in; ngx_buf_tag_t tag; idx = luaL_checkint(L, 2); dd("index: %d", idx); if (idx != 1 && idx != 2) { return luaL_error(L, "bad index: %d", idx); } if (idx == 2) { /* overwriting the eof flag */ last = lua_toboolean(L, 3); lua_getglobal(L, ngx_http_lua_chain_key); in = lua_touserdata(L, -1); if (last) { ctx->seen_last_in_filter = 1; for (cl = in; cl; cl = cl->next) { if (cl->next == NULL) { if (r == r->main) { cl->buf->last_buf = 1; } else { cl->buf->last_in_chain = 1; } break; } } } else { /* last == 0 */ found = 0; for (cl = in; cl; cl = cl->next) { if (cl->buf->last_buf) { cl->buf->last_buf = 0; found = 1; } if (cl->buf->last_in_chain) { cl->buf->last_in_chain = 0; found = 1; } if (found && cl->buf->last - cl->buf->pos == 0) { /* make it a special sync buf to make * ngx_http_write_filter_module happy. */ cl->buf->temporary = 0; cl->buf->memory = 0; cl->buf->mmap = 0; cl->buf->in_file = 0; cl->buf->sync = 1; } } } return 0; } /* idx == 1, overwriting the chunk data */ type = lua_type(L, 3); switch (type) { case LUA_TSTRING: case LUA_TNUMBER: data = (u_char *) lua_tolstring(L, 3, &size); break; case LUA_TNIL: /* discard the buffers */ lua_getglobal(L, ngx_http_lua_chain_key); /* key val */ in = lua_touserdata(L, -1); lua_pop(L, 1); lua_pushliteral(L, ngx_http_lua_chain_key); /* key */ for (cl = in; cl; cl = cl->next) { dd("mark the buf as consumed: %d", (int) ngx_buf_size(cl->buf)); cl->buf->pos = cl->buf->last; /* will later be skipped by ngx_http_lua_body_filter() * and never be forwarded to the next filters. */ } return 0; case LUA_TTABLE: size = ngx_http_lua_calc_strlen_in_table(L, 3 /* index */, 3 /* arg */, 1 /* strict */); data = NULL; break; default: return luaL_error(L, "bad chunk data type: %s", lua_typename(L, type)); } lua_getglobal(L, ngx_http_lua_chain_key); in = lua_touserdata(L, -1); lua_pop(L, 1); last = 0; for (cl = in; cl; cl = cl->next) { if (cl->buf->last_buf || cl->buf->last_in_chain) { last = 1; } dd("mark the buf as consumed: %d", (int) ngx_buf_size(cl->buf)); cl->buf->pos = cl->buf->last; /* will later be skipped by ngx_http_lua_body_filter() and * never be forwarded to the next filters */ } if (size == 0 && !last) { return 0; } tag = (ngx_buf_tag_t) &ngx_http_lua_module; cl = ngx_http_lua_chains_get_free_buf(r->connection->log, r->pool, &ctx->free_bufs, size, tag); if (cl == NULL) { return luaL_error(L, "out of memory"); } if (size == 0) { /* "last" must already be set */ if (r == r->main) { cl->buf->last_buf = 1; } else { cl->buf->last_in_chain = 1; } return 0; } if (type == LUA_TTABLE) { cl->buf->last = ngx_http_lua_copy_str_in_table(L, 3, cl->buf->last); } else { cl->buf->last = ngx_copy(cl->buf->pos, data, size); } if (last) { ctx->seen_last_in_filter = 1; if (r == r->main) { cl->buf->last_buf = 1; } else { cl->buf->last_in_chain = 1; } } lua_pushlightuserdata(L, cl); lua_setglobal(L, ngx_http_lua_chain_key); return 0; }