Skip to content

Commit 4ecadd5

Browse files
committed
feat: add precontent_by_*
1 parent abab54f commit 4ecadd5

18 files changed

+1071
-4
lines changed

README.markdown

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,8 @@ Directives
11401140
* [set_by_lua](#set_by_lua)
11411141
* [set_by_lua_block](#set_by_lua_block)
11421142
* [set_by_lua_file](#set_by_lua_file)
1143+
* [precontent_by_lua_block](#precontent_by_lua_block)
1144+
* [precontent_by_lua_file](#precontent_by_lua_file)
11431145
* [content_by_lua](#content_by_lua)
11441146
* [content_by_lua_block](#content_by_lua_block)
11451147
* [content_by_lua_file](#content_by_lua_file)
@@ -1842,6 +1844,67 @@ This directive requires the [ngx_devel_kit](https://github.com/simplresty/ngx_de
18421844

18431845
[Back to TOC](#directives)
18441846

1847+
precontent_by_lua_block
1848+
--------------------
1849+
1850+
**syntax:** *precontent_by_lua_block { lua-script }*
1851+
1852+
**context:** *http, server, location, location if*
1853+
1854+
**phase:** *precontent tail*
1855+
1856+
Acts as a precontent phase handler and executes Lua code string specified in `{ <lua-script }` for every request.
1857+
The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox).
1858+
1859+
Note that this handler always runs *after* the standard [ngx_http_mirror_module](https://nginx.org/en/docs/http/ngx_http_mirror_module.html) and [ngx_http_try_files_module](https://nginx.org/en/docs/http/ngx_http_core_module.html#try_files). For example:
1860+
1861+
```nginx
1862+
location /images/ {
1863+
try_files $uri /images/default.gif;
1864+
precontent_by_lua_block {
1865+
ngx.log(ngx.NOTICE, "file found")
1866+
}
1867+
}
1868+
1869+
location = /images/default.gif {
1870+
expires 30s;
1871+
precontent_by_lua_block {
1872+
ngx.log(ngx.NOTICE, "file not found, use default.gif instead")
1873+
}
1874+
}
1875+
```
1876+
1877+
That is, if a request for /images/foo.jpg comes in and the file does not exist, the request will be internally redirected to /images/default.gif before [precontent_by_lua_block](#precontent_by_lua_block), and then the [precontent_by_lua_block](#precontent_by_lua_block) in new location will run and log "file not found, use default.gif instead".
1878+
1879+
You can use [precontent_by_lua_block](#precontent_by_lua_block) to perform some preparatory functions after the access phase handler but before the proxy or other content handler. Especially some functions that cannot be performed in [balancer_by_lua_block](#balancer_by_lua_block).
1880+
1881+
[Back to TOC](#directives)
1882+
1883+
precontent_by_lua_file
1884+
-------------------
1885+
1886+
**syntax:** *precontent_by_lua_file &lt;path-to-lua-script-file&gt;*
1887+
1888+
**context:** *http, server, location, location if*
1889+
1890+
**phase:** *precontent tail*
1891+
1892+
Equivalent to [precontent_by_lua_block](#precontent_by_lua_block), except that the file specified by `<path-to-lua-script-file>` contains the Lua code, or, as from the `v0.5.0rc32` release, the [LuaJIT bytecode](#luajit-bytecode-support) to be executed.
1893+
1894+
Nginx variables can be used in the `<path-to-lua-script-file>` string to provide flexibility. This however carries some risks and is not ordinarily recommended.
1895+
1896+
When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server.
1897+
1898+
When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached
1899+
and the Nginx config must be reloaded each time the Lua source file is modified.
1900+
The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid repeatedly reloading Nginx.
1901+
1902+
Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file).
1903+
1904+
But be very careful about malicious user inputs and always carefully validate or filter out the user-supplied path components.
1905+
1906+
[Back to TOC](#directives)
1907+
18451908
content_by_lua
18461909
--------------
18471910

@@ -2710,7 +2773,7 @@ directive.
27102773
This Lua code execution context does not support yielding, so Lua APIs that may yield
27112774
(like cosockets and "light threads") are disabled in this context. One can usually work
27122775
around this limitation by doing such operations in an earlier phase handler (like
2713-
[access_by_lua*](#access_by_lua)) and passing along the result into this context
2776+
[precontent_by_lua*](#precontent_by_lua_block)) and passing along the result into this context
27142777
via the [ngx.ctx](#ngxctx) table.
27152778

27162779
This directive was first introduced in the `v0.10.0` release.

config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ HTTP_LUA_SRCS=" \
260260
$ngx_addon_dir/src/ngx_http_lua_exception.c \
261261
$ngx_addon_dir/src/ngx_http_lua_util.c \
262262
$ngx_addon_dir/src/ngx_http_lua_cache.c \
263+
$ngx_addon_dir/src/ngx_http_lua_precontentby.c \
263264
$ngx_addon_dir/src/ngx_http_lua_contentby.c \
264265
$ngx_addon_dir/src/ngx_http_lua_server_rewriteby.c \
265266
$ngx_addon_dir/src/ngx_http_lua_rewriteby.c \
@@ -327,6 +328,7 @@ HTTP_LUA_DEPS=" \
327328
$ngx_addon_dir/src/ngx_http_lua_exception.h \
328329
$ngx_addon_dir/src/ngx_http_lua_util.h \
329330
$ngx_addon_dir/src/ngx_http_lua_cache.h \
331+
$ngx_addon_dir/src/ngx_http_lua_precontentby.h \
330332
$ngx_addon_dir/src/ngx_http_lua_contentby.h \
331333
$ngx_addon_dir/src/ngx_http_lua_server_rewriteby.c \
332334
$ngx_addon_dir/src/ngx_http_lua_rewriteby.h \

doc/HttpLuaModule.wiki

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,6 +1491,59 @@ switching [[#lua_code_cache|lua_code_cache]] <code>off</code> in <code>nginx.con
14911491
14921492
This directive requires the [https://github.com/simplresty/ngx_devel_kit ngx_devel_kit] module.
14931493
1494+
== precontent_by_lua_block ==
1495+
1496+
'''syntax:''' ''precontent_by_lua_block { lua-script }''
1497+
1498+
'''context:''' ''http, server, location, location if''
1499+
1500+
'''phase:''' ''pre-content tail''
1501+
1502+
Acts as a precontent phase handler and executes Lua code string specified in <code>{ <lua-script }</code> for every request.
1503+
The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox).
1504+
1505+
Note that this handler always runs *after* the standard [[HttpMirrorModule]] and [[HttpTryFilesModule]]. For example:
1506+
1507+
<geshi lang="nginx">
1508+
location /images/ {
1509+
try_files $uri /images/default.gif;
1510+
precontent_by_lua_block {
1511+
ngx.log(ngx.NOTICE, "file found")
1512+
}
1513+
}
1514+
1515+
location = /images/default.gif {
1516+
expires 30s;
1517+
precontent_by_lua_block {
1518+
ngx.log(ngx.NOTICE, "file not found, use default.gif instead")
1519+
}
1520+
}
1521+
</geshi>
1522+
1523+
That is, if a request for /images/foo.jpg comes in and the file does not exist, the request will be internally redirected to /images/default.gif before [[#precontent_by_lua_block|precontent_by_lua_block]], and then the [[#precontent_by_lua_block|precontent_by_lua_block]] in new location will run and log "file not found, use default.gif instead".
1524+
1525+
You can use [[#precontent_by_lua_block|precontent_by_lua_block]] to perform some preparatory functions after the access phase handler but before the proxy or other content handler. Especially some functions that cannot be performed in [[#balancer_by_lua_block|balancer_by_lua_block]].
1526+
1527+
== precontent_by_lua_file ==
1528+
1529+
'''syntax:''' ''precontent_by_lua_file <path-to-lua-script-file>''
1530+
1531+
'''context:''' ''http, server, location, location if''
1532+
1533+
'''phase:''' ''precontent tail''
1534+
1535+
Equivalent to [[#precontent_by_lua_block|precontent_by_lua_block]], except that the file specified by <code><path-to-lua-script-file></code> contains the Lua code, or, as from the <code>v0.5.0rc32</code> release, the [[#LuaJIT bytecode support|LuaJIT bytecode]] to be executed.
1536+
1537+
Nginx variables can be used in the <code><path-to-lua-script-file></code> string to provide flexibility. This however carries some risks and is not ordinarily recommended.
1538+
1539+
When a relative path like <code>foo/bar.lua</code> is given, they will be turned into the absolute path relative to the <code>server prefix</code> path determined by the <code>-p PATH</code> command-line option while starting the Nginx server.
1540+
1541+
When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached
1542+
and the Nginx config must be reloaded each time the Lua source file is modified.
1543+
The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] <code>off</code> in <code>nginx.conf</code> to avoid repeatedly reloading Nginx.
1544+
1545+
Nginx variables are supported in the file path for dynamic dispatch just as in [[#content_by_lua_file|content_by_lua_file]].
1546+
14941547
== content_by_lua ==
14951548
14961549
'''syntax:''' ''content_by_lua <lua-script-str>''

src/ngx_http_lua_common.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ typedef struct {
148148
#define NGX_HTTP_LUA_CONTEXT_EXIT_WORKER 0x00002000
149149
#define NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO 0x00004000
150150
#define NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE 0x00008000
151+
#define NGX_HTTP_LUA_CONTEXT_PRECONTENT 0x00020000
151152

152153
#ifdef HAVE_PROXY_SSL_PATCH
153154
#define NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY 0x00010000
@@ -254,6 +255,7 @@ struct ngx_http_lua_main_conf_s {
254255

255256
ngx_flag_t postponed_to_rewrite_phase_end;
256257
ngx_flag_t postponed_to_access_phase_end;
258+
ngx_flag_t postponed_to_precontent_phase_end;
257259

258260
ngx_http_lua_main_conf_handler_pt init_handler;
259261
ngx_str_t init_src;
@@ -322,6 +324,7 @@ struct ngx_http_lua_main_conf_s {
322324
unsigned requires_shm:1;
323325
unsigned requires_capture_log:1;
324326
unsigned requires_server_rewrite:1;
327+
unsigned requires_precontent:1;
325328
};
326329

327330

@@ -414,6 +417,7 @@ struct ngx_http_lua_loc_conf_s {
414417

415418
ngx_http_handler_pt rewrite_handler;
416419
ngx_http_handler_pt access_handler;
420+
ngx_http_handler_pt precontent_handler;
417421
ngx_http_handler_pt content_handler;
418422
ngx_http_handler_pt log_handler;
419423
ngx_http_handler_pt header_filter_handler;
@@ -438,13 +442,22 @@ struct ngx_http_lua_loc_conf_s {
438442
u_char *access_src_key; /* cached key for access_src */
439443
int access_src_ref;
440444

445+
u_char *precontent_chunkname;
446+
ngx_http_complex_value_t precontent_src; /* precontent_by_lua
447+
inline script/script
448+
file path */
449+
450+
u_char *precontent_src_key; /* cached key for
451+
precontent_src */
452+
int precontent_src_ref;
453+
441454
u_char *content_chunkname;
442455
ngx_http_complex_value_t content_src; /* content_by_lua
443456
inline script/script
444457
file path */
445458

446-
u_char *content_src_key; /* cached key for content_src */
447-
int content_src_ref;
459+
u_char *content_src_key; /* cached key for content_src */
460+
int content_src_ref;
448461

449462

450463
u_char *log_chunkname;
@@ -683,6 +696,7 @@ typedef struct ngx_http_lua_ctx_s {
683696
unsigned entered_server_rewrite_phase:1;
684697
unsigned entered_rewrite_phase:1;
685698
unsigned entered_access_phase:1;
699+
unsigned entered_precontent_phase:1;
686700
unsigned entered_content_phase:1;
687701

688702
unsigned buffering:1; /* HTTP 1.0 response body buffering flag */

src/ngx_http_lua_control.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ ngx_http_lua_ngx_exec(lua_State *L)
9393
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
9494
| NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE
9595
| NGX_HTTP_LUA_CONTEXT_ACCESS
96+
| NGX_HTTP_LUA_CONTEXT_PRECONTENT
9697
| NGX_HTTP_LUA_CONTEXT_CONTENT);
9798

9899
ngx_http_lua_check_if_abortable(L, ctx);
@@ -235,6 +236,7 @@ ngx_http_lua_ngx_redirect(lua_State *L)
235236
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
236237
| NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE
237238
| NGX_HTTP_LUA_CONTEXT_ACCESS
239+
| NGX_HTTP_LUA_CONTEXT_PRECONTENT
238240
| NGX_HTTP_LUA_CONTEXT_CONTENT);
239241

240242
ngx_http_lua_check_if_abortable(L, ctx);
@@ -380,6 +382,7 @@ ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err,
380382
if (ngx_http_lua_ffi_check_context(ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
381383
| NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE
382384
| NGX_HTTP_LUA_CONTEXT_ACCESS
385+
| NGX_HTTP_LUA_CONTEXT_PRECONTENT
383386
| NGX_HTTP_LUA_CONTEXT_CONTENT
384387
| NGX_HTTP_LUA_CONTEXT_TIMER
385388
| NGX_HTTP_LUA_CONTEXT_HEADER_FILTER

src/ngx_http_lua_directive.c

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "ngx_http_lua_directive.h"
1616
#include "ngx_http_lua_util.h"
1717
#include "ngx_http_lua_cache.h"
18+
#include "ngx_http_lua_precontentby.h"
1819
#include "ngx_http_lua_contentby.h"
1920
#include "ngx_http_lua_accessby.h"
2021
#include "ngx_http_lua_server_rewriteby.h"
@@ -798,6 +799,111 @@ ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
798799
}
799800

800801

802+
char *
803+
ngx_http_lua_precontent_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
804+
void *conf)
805+
{
806+
char *rv;
807+
ngx_conf_t save;
808+
809+
save = *cf;
810+
cf->handler = ngx_http_lua_precontent_by_lua;
811+
cf->handler_conf = conf;
812+
813+
rv = ngx_http_lua_conf_lua_block_parse(cf, cmd);
814+
815+
*cf = save;
816+
817+
return rv;
818+
}
819+
820+
821+
char *
822+
ngx_http_lua_precontent_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
823+
{
824+
size_t chunkname_len;
825+
u_char *cache_key = NULL, *chunkname;
826+
ngx_str_t *value;
827+
ngx_http_core_loc_conf_t *clcf;
828+
ngx_http_lua_main_conf_t *lmcf;
829+
ngx_http_lua_loc_conf_t *llcf = conf;
830+
831+
ngx_http_compile_complex_value_t ccv;
832+
833+
dd("enter");
834+
835+
/* must specify a content handler */
836+
if (cmd->post == NULL) {
837+
return NGX_CONF_ERROR;
838+
}
839+
840+
if (llcf->precontent_handler) {
841+
return "is duplicate";
842+
}
843+
844+
value = cf->args->elts;
845+
846+
dd("value[0]: %.*s", (int) value[0].len, value[0].data);
847+
dd("value[1]: %.*s", (int) value[1].len, value[1].data);
848+
849+
if (value[1].len == 0) {
850+
/* Oops...Invalid location conf */
851+
ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
852+
"invalid location config: no runnable Lua code");
853+
return NGX_CONF_ERROR;
854+
}
855+
856+
if (cmd->post == ngx_http_lua_precontent_handler_inline) {
857+
chunkname = ngx_http_lua_gen_chunk_name(cf, "precontent_by_lua",
858+
sizeof("precontent_by_lua") - 1,
859+
&chunkname_len);
860+
if (chunkname == NULL) {
861+
return NGX_CONF_ERROR;
862+
}
863+
864+
cache_key = ngx_http_lua_gen_chunk_cache_key(cf, "precontent_by_lua",
865+
value[1].data,
866+
value[1].len);
867+
if (cache_key == NULL) {
868+
return NGX_CONF_ERROR;
869+
}
870+
871+
/* Don't eval nginx variables for inline lua code */
872+
llcf->precontent_src.value = value[1];
873+
llcf->precontent_chunkname = chunkname;
874+
875+
} else {
876+
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
877+
ccv.cf = cf;
878+
ccv.value = &value[1];
879+
ccv.complex_value = &llcf->precontent_src;
880+
881+
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
882+
return NGX_CONF_ERROR;
883+
}
884+
885+
if (llcf->precontent_src.lengths == NULL) {
886+
/* no variable found */
887+
cache_key = ngx_http_lua_gen_file_cache_key(cf, value[1].data,
888+
value[1].len);
889+
if (cache_key == NULL) {
890+
return NGX_CONF_ERROR;
891+
}
892+
}
893+
}
894+
895+
llcf->precontent_src_key = cache_key;
896+
llcf->precontent_handler = (ngx_http_handler_pt) cmd->post;
897+
898+
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module);
899+
900+
lmcf->requires_precontent = 1;
901+
lmcf->requires_capture_filter = 1;
902+
903+
return NGX_CONF_OK;
904+
}
905+
906+
801907
char *
802908
ngx_http_lua_content_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
803909
void *conf)

src/ngx_http_lua_directive.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ char *ngx_http_lua_regex_cache_max_entries(ngx_conf_t *cf, ngx_command_t *cmd,
2121
void *conf);
2222
char *ngx_http_lua_regex_match_limit(ngx_conf_t *cf, ngx_command_t *cmd,
2323
void *conf);
24+
char *ngx_http_lua_precontent_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
25+
void *conf);
26+
char *ngx_http_lua_precontent_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
27+
void *conf);
2428
char *ngx_http_lua_content_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
2529
void *conf);
2630
char *ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,

0 commit comments

Comments
 (0)