diff --git a/README.markdown b/README.markdown
index 6839efc6bd..7309633383 100644
--- a/README.markdown
+++ b/README.markdown
@@ -5460,7 +5460,7 @@ ngx.exit
**syntax:** *ngx.exit(status)*
-**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua**
+**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua**
When `status >= 200` (i.e., `ngx.HTTP_OK` and above), it will interrupt the execution of the current request and return status code to Nginx.
@@ -5505,7 +5505,7 @@ Note that while this method accepts all [HTTP status constants](#http-status-con
Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the `return` statement, i.e., `return ngx.exit(...)` be used to reinforce the fact that the request processing is being terminated.
-When being used in the contexts of [header_filter_by_lua*](#header_filter_by_lua), [balancer_by_lua*](#balancer_by_lua_block), and
+When being used in the contexts of [header_filter_by_lua*](#header_filter_by_lua), [body_filter_by_lua*](#body_filter_by_lua_block), [balancer_by_lua*](#balancer_by_lua_block), and
[ssl_session_store_by_lua*](#ssl_session_store_by_lua_block), `ngx.exit()` is
an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use `return` in combination as suggested above.
diff --git a/doc/HttpLuaModule.wiki b/doc/HttpLuaModule.wiki
index 91409d2109..4129f7b4f9 100644
--- a/doc/HttpLuaModule.wiki
+++ b/doc/HttpLuaModule.wiki
@@ -4579,7 +4579,7 @@ Since v0.8.3
this function returns 1
on success, or re
'''syntax:''' ''ngx.exit(status)''
-'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*''
+'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*''
When status >= 200
(i.e., ngx.HTTP_OK
and above), it will interrupt the execution of the current request and return status code to Nginx.
@@ -4621,7 +4621,7 @@ Note that while this method accepts all [[#HTTP status constants|HTTP status con
Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the return
statement, i.e., return ngx.exit(...)
be used to reinforce the fact that the request processing is being terminated.
-When being used in the contexts of [[#header_filter_by_lua|header_filter_by_lua*]], [[#balancer_by_lua_block|balancer_by_lua*]], and
+When being used in the contexts of [[#header_filter_by_lua|header_filter_by_lua*]], [[#body_filter_by_lua_block|body_filter_by_lua*]], [[#balancer_by_lua_block|balancer_by_lua*]], and
[[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]], ngx.exit()
is
an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use return
in combination as suggested above.
diff --git a/src/ngx_http_lua_bodyfilterby.c b/src/ngx_http_lua_bodyfilterby.c
index 75608695e1..b9c493f084 100644
--- a/src/ngx_http_lua_bodyfilterby.c
+++ b/src/ngx_http_lua_bodyfilterby.c
@@ -82,12 +82,15 @@ ngx_int_t
ngx_http_lua_body_filter_by_chunk(lua_State *L, ngx_http_request_t *r,
ngx_chain_t *in)
{
- ngx_int_t rc;
- u_char *err_msg;
- size_t len;
+ ngx_int_t rc;
+ u_char *err_msg;
+ size_t len;
#if (NGX_PCRE)
- ngx_pool_t *old_pool;
+ ngx_pool_t *old_pool;
#endif
+ ngx_http_lua_ctx_t *ctx;
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
dd("initialize nginx context in Lua VM, code chunk at stack top sp = 1");
ngx_http_lua_body_filter_by_lua_env(L, r, in);
@@ -110,6 +113,8 @@ ngx_http_lua_body_filter_by_chunk(lua_State *L, ngx_http_request_t *r,
ngx_http_lua_pcre_malloc_done(old_pool);
#endif
+ dd("rc == %d", (int) rc);
+
if (rc != 0) {
/* error occurred */
@@ -136,7 +141,10 @@ ngx_http_lua_body_filter_by_chunk(lua_State *L, ngx_http_request_t *r,
lua_settop(L, 0);
- if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+ if (ctx->body_filter_aborted
+ || rc == NGX_ERROR
+ || rc >= NGX_HTTP_SPECIAL_RESPONSE)
+ {
return NGX_ERROR;
}
@@ -166,15 +174,9 @@ ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in)
return NGX_ERROR;
}
- rc = ngx_http_lua_body_filter_by_chunk(L, r, in);
-
- dd("body filter by chunk returns %d", (int) rc);
-
- if (rc != NGX_OK) {
- return NGX_ERROR;
- }
+ dd("calling body filter by chunk");
- return NGX_OK;
+ return ngx_http_lua_body_filter_by_chunk(L, r, in);
}
@@ -216,13 +218,7 @@ ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in)
/* make sure we have a valid code chunk */
ngx_http_lua_assert(lua_isfunction(L, -1));
- rc = ngx_http_lua_body_filter_by_chunk(L, r, in);
-
- if (rc != NGX_OK) {
- return NGX_ERROR;
- }
-
- return NGX_OK;
+ return ngx_http_lua_body_filter_by_chunk(L, r, in);
}
@@ -262,6 +258,12 @@ ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
}
+ if (ctx->body_filter_aborted) {
+ /* maybe there is a bug in the output body filter caller, other
+ * outputs will be intercepted here */
+ 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));
diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h
index 781a2454a1..7eb113127d 100644
--- a/src/ngx_http_lua_common.h
+++ b/src/ngx_http_lua_common.h
@@ -559,6 +559,8 @@ typedef struct ngx_http_lua_ctx_s {
unsigned exited:1;
+ unsigned body_filter_aborted:1;
+
unsigned eof:1; /* 1: last_buf has been sent;
0: last_buf not sent yet */
diff --git a/src/ngx_http_lua_control.c b/src/ngx_http_lua_control.c
index 3d92d88e23..d6f86061cb 100644
--- a/src/ngx_http_lua_control.c
+++ b/src/ngx_http_lua_control.c
@@ -365,6 +365,7 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err,
| NGX_HTTP_LUA_CONTEXT_CONTENT
| NGX_HTTP_LUA_CONTEXT_TIMER
| NGX_HTTP_LUA_CONTEXT_HEADER_FILTER
+ | NGX_HTTP_LUA_CONTEXT_BODY_FILTER
| NGX_HTTP_LUA_CONTEXT_BALANCER
| NGX_HTTP_LUA_CONTEXT_SSL_CERT
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE
@@ -375,6 +376,19 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err,
return NGX_ERROR;
}
+ if (ctx->context & NGX_HTTP_LUA_CONTEXT_BODY_FILTER) {
+
+ if (status != NGX_ERROR && status != NGX_HTTP_CLOSE) {
+ *errlen = ngx_snprintf(err, *errlen, "attempt to exit with the "
+ "code not 444 or ngx.ERROR")
+ - err;
+ return NGX_ERROR;
+ }
+
+ ctx->body_filter_aborted = 1;
+ return NGX_DONE;
+ }
+
if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SSL_CERT
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH))
diff --git a/t/082-body-filter.t b/t/082-body-filter.t
index 5f765fa439..a84bc99a9b 100644
--- a/t/082-body-filter.t
+++ b/t/082-body-filter.t
@@ -10,7 +10,7 @@ log_level('debug');
repeat_each(2);
-plan tests => repeat_each() * (blocks() * 3 + 11);
+plan tests => repeat_each() * (blocks() * 3 + 8);
#no_diff();
no_long_string();
@@ -838,3 +838,46 @@ GET /lua
--- ignore_response
--- error_log
API disabled in the context of body_filter_by_lua*
+
+
+
+=== TEST 27: exit 444
+--- config
+ location = /t {
+ content_by_lua_block {
+ ngx.say("111")
+ ngx.say("222")
+ ngx.say("333")
+ }
+
+ body_filter_by_lua_block {
+ ngx.exit(444)
+ }
+ }
+--- request
+ GET /t
+--- ignore_response
+--- no_error_log
+[error]
+[alert]
+
+
+
+=== TEST 28: exit OK
+--- config
+ location = /t {
+ content_by_lua_block {
+ ngx.say("111")
+ ngx.say("222")
+ ngx.say("333")
+ }
+
+ body_filter_by_lua_block {
+ ngx.exit(200)
+ }
+ }
+--- request
+ GET /t
+--- ignore_response
+--- error_log
+attempt to exit with the code not 444 or ngx.ERROR