Skip to content

Commit 2bc2e81

Browse files
authored
feature: add precontent_by_lua directives
1 parent ec950f8 commit 2bc2e81

18 files changed

+1145
-53
lines changed

README.markdown

Lines changed: 81 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)
@@ -1196,6 +1198,7 @@ Directives
11961198
* [lua_http10_buffering](#lua_http10_buffering)
11971199
* [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone)
11981200
* [access_by_lua_no_postpone](#access_by_lua_no_postpone)
1201+
* [precontent_by_lua_no_postpone](#precontent_by_lua_no_postpone)
11991202
* [lua_transform_underscores_in_response_headers](#lua_transform_underscores_in_response_headers)
12001203
* [lua_check_client_abort](#lua_check_client_abort)
12011204
* [lua_max_pending_timers](#lua_max_pending_timers)
@@ -1842,6 +1845,70 @@ This directive requires the [ngx_devel_kit](https://github.com/simplresty/ngx_de
18421845

18431846
[Back to TOC](#directives)
18441847

1848+
precontent_by_lua_block
1849+
--------------------
1850+
1851+
**syntax:** *precontent_by_lua_block { lua-script }*
1852+
1853+
**context:** *http, server, location, location if*
1854+
1855+
**phase:** *precontent tail*
1856+
1857+
Acts as a precontent phase handler and executes Lua code string specified in `{ <lua-script }` for every request.
1858+
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).
1859+
1860+
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:
1861+
1862+
```nginx
1863+
location /images/ {
1864+
try_files $uri /images/default.gif;
1865+
precontent_by_lua_block {
1866+
ngx.log(ngx.NOTICE, "file found")
1867+
}
1868+
}
1869+
1870+
location = /images/default.gif {
1871+
expires 30s;
1872+
precontent_by_lua_block {
1873+
ngx.log(ngx.NOTICE, "file not found, use default.gif instead")
1874+
}
1875+
}
1876+
```
1877+
1878+
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".
1879+
1880+
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).
1881+
1882+
you can use the [precontent_by_lua_no_postpone](#precontent_by_lua_no_postpone) directive to control when to run this handler inside the "precontent" request-processing phase
1883+
of Nginx.
1884+
1885+
[Back to TOC](#directives)
1886+
1887+
precontent_by_lua_file
1888+
-------------------
1889+
1890+
**syntax:** *precontent_by_lua_file &lt;path-to-lua-script-file&gt;*
1891+
1892+
**context:** *http, server, location, location if*
1893+
1894+
**phase:** *precontent tail*
1895+
1896+
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.
1897+
1898+
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.
1899+
1900+
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.
1901+
1902+
When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached
1903+
and the Nginx config must be reloaded each time the Lua source file is modified.
1904+
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.
1905+
1906+
Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file).
1907+
1908+
But be very careful about malicious user inputs and always carefully validate or filter out the user-supplied path components.
1909+
1910+
[Back to TOC](#directives)
1911+
18451912
content_by_lua
18461913
--------------
18471914

@@ -2710,7 +2777,7 @@ directive.
27102777
This Lua code execution context does not support yielding, so Lua APIs that may yield
27112778
(like cosockets and "light threads") are disabled in this context. One can usually work
27122779
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
2780+
[precontent_by_lua*](#precontent_by_lua_block)) and passing along the result into this context
27142781
via the [ngx.ctx](#ngxctx) table.
27152782

27162783
This directive was first introduced in the `v0.10.0` release.
@@ -3647,6 +3714,19 @@ This directive was first introduced in the `v0.9.20` release.
36473714

36483715
[Back to TOC](#directives)
36493716

3717+
precontent_by_lua_no_postpone
3718+
-------------------------
3719+
3720+
**syntax:** *precontent_by_lua_no_postpone on|off*
3721+
3722+
**default:** *precontent_by_lua_no_postpone off*
3723+
3724+
**context:** *http*
3725+
3726+
Controls whether or not to disable postponing [precontent_by_lua*](#precontent_by_lua_block) directives to run at the end of the `precontent` request-processing phase. By default, this directive is turned off and the Lua code is postponed to run at the end of the `precontent` phase.
3727+
3728+
[Back to TOC](#directives)
3729+
36503730
lua_transform_underscores_in_response_headers
36513731
---------------------------------------------
36523732

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: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,6 +1491,61 @@ 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+
You can use the [[#precontent_by_lua_no_postpone|precontent_by_lua_no_postpone]] directive to control when to run this handler inside the "precontent" request-processing phase of Nginx.
1528+
1529+
== precontent_by_lua_file ==
1530+
1531+
'''syntax:''' ''precontent_by_lua_file <path-to-lua-script-file>''
1532+
1533+
'''context:''' ''http, server, location, location if''
1534+
1535+
'''phase:''' ''precontent tail''
1536+
1537+
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.
1538+
1539+
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.
1540+
1541+
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.
1542+
1543+
When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached
1544+
and the Nginx config must be reloaded each time the Lua source file is modified.
1545+
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.
1546+
1547+
Nginx variables are supported in the file path for dynamic dispatch just as in [[#content_by_lua_file|content_by_lua_file]].
1548+
14941549
== content_by_lua ==
14951550
14961551
'''syntax:''' ''content_by_lua <lua-script-str>''
@@ -3017,6 +3072,16 @@ Controls whether or not to disable postponing [[#access_by_lua|access_by_lua*]]
30173072
30183073
This directive was first introduced in the <code>v0.9.20</code> release.
30193074
3075+
== precontent_by_lua_no_postpone ==
3076+
3077+
'''syntax:''' ''precontent_by_lua_no_postpone on|off''
3078+
3079+
'''default:''' ''precontent_by_lua_no_postpone off''
3080+
3081+
'''context:''' ''http''
3082+
3083+
Controls whether or not to disable postponing [[#precontent_by_lua_block|precontent_by_lua_block*]] directives to run at the end of the <code>precontent</code> request-processing phase. By default, this directive is turned off and the Lua code is postponed to run at the end of the <code>precontent</code> phase.
3084+
30203085
== lua_transform_underscores_in_response_headers ==
30213086
30223087
'''syntax:''' ''lua_transform_underscores_in_response_headers on|off''

src/ngx_http_lua_common.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,8 @@ 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-
152-
#ifdef HAVE_PROXY_SSL_PATCH
153151
#define NGX_HTTP_LUA_CONTEXT_PROXY_SSL_VERIFY 0x00010000
154-
#endif
152+
#define NGX_HTTP_LUA_CONTEXT_PRECONTENT 0x00020000
155153

156154

157155
#define NGX_HTTP_LUA_FFI_NO_REQ_CTX -100
@@ -254,6 +252,7 @@ struct ngx_http_lua_main_conf_s {
254252

255253
ngx_flag_t postponed_to_rewrite_phase_end;
256254
ngx_flag_t postponed_to_access_phase_end;
255+
ngx_flag_t postponed_to_precontent_phase_end;
257256

258257
ngx_http_lua_main_conf_handler_pt init_handler;
259258
ngx_str_t init_src;
@@ -322,6 +321,7 @@ struct ngx_http_lua_main_conf_s {
322321
unsigned requires_shm:1;
323322
unsigned requires_capture_log:1;
324323
unsigned requires_server_rewrite:1;
324+
unsigned requires_precontent:1;
325325
};
326326

327327

@@ -414,6 +414,7 @@ struct ngx_http_lua_loc_conf_s {
414414

415415
ngx_http_handler_pt rewrite_handler;
416416
ngx_http_handler_pt access_handler;
417+
ngx_http_handler_pt precontent_handler;
417418
ngx_http_handler_pt content_handler;
418419
ngx_http_handler_pt log_handler;
419420
ngx_http_handler_pt header_filter_handler;
@@ -438,13 +439,22 @@ struct ngx_http_lua_loc_conf_s {
438439
u_char *access_src_key; /* cached key for access_src */
439440
int access_src_ref;
440441

442+
u_char *precontent_chunkname;
443+
ngx_http_complex_value_t precontent_src; /* precontent_by_lua
444+
inline script/script
445+
file path */
446+
447+
u_char *precontent_src_key; /* cached key for
448+
precontent_src */
449+
int precontent_src_ref;
450+
441451
u_char *content_chunkname;
442452
ngx_http_complex_value_t content_src; /* content_by_lua
443453
inline script/script
444454
file path */
445455

446-
u_char *content_src_key; /* cached key for content_src */
447-
int content_src_ref;
456+
u_char *content_src_key; /* cached key for content_src */
457+
int content_src_ref;
448458

449459

450460
u_char *log_chunkname;
@@ -683,6 +693,7 @@ typedef struct ngx_http_lua_ctx_s {
683693
unsigned entered_server_rewrite_phase:1;
684694
unsigned entered_rewrite_phase:1;
685695
unsigned entered_access_phase:1;
696+
unsigned entered_precontent_phase:1;
686697
unsigned entered_content_phase:1;
687698

688699
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

0 commit comments

Comments
 (0)