resolved conflicts while merging the "master" branch to "shm".
This commit is contained in:
Коммит
b71a0b52a6
|
@ -120,6 +120,8 @@ src/headers.[ch]
|
|||
src/script.[ch]
|
||||
src/filter.[ch]
|
||||
src/shdict.[ch]
|
||||
src/body.[ch]
|
||||
src/uri.[ch]
|
||||
a.patch
|
||||
all
|
||||
build1[01]
|
||||
|
|
883
README
883
README
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
428
README.markdown
428
README.markdown
|
@ -13,7 +13,7 @@ This module is under active development and is already production ready.
|
|||
Version
|
||||
=======
|
||||
|
||||
This document describes ngx_lua [v0.3.1rc9](https://github.com/chaoslawful/lua-nginx-module/downloads) released on 9 October 2011.
|
||||
This document describes ngx_lua [v0.3.1rc20](https://github.com/chaoslawful/lua-nginx-module/tags) released on 24 October 2011.
|
||||
|
||||
Synopsis
|
||||
========
|
||||
|
@ -310,6 +310,7 @@ Note that [set_by_lua](http://wiki.nginx.org/HttpLuaModule#set_by_lua) can only
|
|||
a time. But a work-around is also available by means of the [ngx.var.VARIABLE](http://wiki.nginx.org/HttpLuaModule#ngx.var.VARIABLE) interface,
|
||||
for example,
|
||||
|
||||
|
||||
location /foo {
|
||||
set $diff ''; # we have to predefine the $diff variable here
|
||||
|
||||
|
@ -327,6 +328,7 @@ for example,
|
|||
|
||||
This directive can be freely mixed with all the directives of [HttpRewriteModule](http://wiki.nginx.org/HttpRewriteModule), [HttpSetMiscModule](http://wiki.nginx.org/HttpSetMiscModule), and [HttpArrayVarModule](http://wiki.nginx.org/HttpArrayVarModule). All of these directives will run in exactly the same order that they are written in the config file. For example,
|
||||
|
||||
|
||||
set $foo 32;
|
||||
set_by_lua $bar 'tonumber(ngx.var.foo) + 1';
|
||||
set $baz "bar: $bar"; # $baz == "bar: 33"
|
||||
|
@ -336,11 +338,12 @@ This directive requires the [ngx_devel_kit](https://github.com/simpl/ngx_devel_k
|
|||
|
||||
set_by_lua_file
|
||||
---------------
|
||||
|
||||
**syntax:** *set_by_lua_file $res <path-to-lua-script> [$arg1 $arg2 ...]*
|
||||
|
||||
**context:** *main, server, location, server if, location if*
|
||||
|
||||
**phase:** *rewrite*
|
||||
|
||||
Basically the same as [set_by_lua](http://wiki.nginx.org/HttpLuaModule#set_by_lua), except the code to be executed is in the
|
||||
file specified by `<path-lua-script>`.
|
||||
|
||||
|
@ -393,7 +396,7 @@ rewrite_by_lua
|
|||
|
||||
**context:** *http, server, location, location if*
|
||||
|
||||
**phase:** *rewrite tail*
|
||||
**phase:** *post-rewrite*
|
||||
|
||||
Act as a rewrite phase handler and execute user code specified by `<lua-script-str>`
|
||||
for every request. The user code may call predefined APIs to generate response
|
||||
|
@ -490,6 +493,20 @@ Just as any other rewrite phase handlers, [rewrite_by_lua](http://wiki.nginx.org
|
|||
|
||||
Note that calling `ngx.exit(ngx.OK)` just returning from the current [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) handler, and the nginx request processing control flow will still continue to the content handler. To terminate the current request from within the current [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) handler, calling [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures.
|
||||
|
||||
If one uses [HttpRewriteModule](http://wiki.nginx.org/HttpRewriteModule)'s [rewrite](http://wiki.nginx.org/HttpRewriteModule#rewrite) directive to change the URI and initiate location re-lookups (kinda like internal redirections), then [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) and [rewrite_by_lua_file](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua_file) will be skipped altogether in the current location. For example,
|
||||
|
||||
|
||||
location /foo {
|
||||
rewrite ^ /bar;
|
||||
rewrite_by_lua 'ngx.exit(503)';
|
||||
}
|
||||
location /bar {
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
Here the Lua code `ngx.exit(503)` will never run while all the Lua code (except access phase handlers) in the `/bar` location will not be affected anyway. Similarly, `rewrite ^ /bar last` will also initiate a location re-lookup. If you use the `break` modifier for the [rewrite](http://wiki.nginx.org/HttpRewriteModule#rewrite) directive, however, no location re-lookup will be triggered, and therefore, the rewrite-phase Lua code will still be run as normal.
|
||||
|
||||
rewrite_by_lua_file
|
||||
-------------------
|
||||
|
||||
|
@ -497,7 +514,7 @@ rewrite_by_lua_file
|
|||
|
||||
**context:** *http, server, location, location if*
|
||||
|
||||
**phase:** *rewrite tail*
|
||||
**phase:** *post-rewrite*
|
||||
|
||||
Same as [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua), except the code to be executed is in
|
||||
the file specified by `<path-lua-script>`.
|
||||
|
@ -518,7 +535,7 @@ access_by_lua
|
|||
|
||||
**context:** *http, server, location, location if*
|
||||
|
||||
**phase:** *access tail*
|
||||
**phase:** *post-access*
|
||||
|
||||
Act as an access phase handler and execute user code specified by `<lua-script-str>` for every request. The user code may call predefined APIs to generate response content.
|
||||
|
||||
|
@ -587,7 +604,7 @@ access_by_lua_file
|
|||
|
||||
**context:** *http, server, location, location if*
|
||||
|
||||
**phase:** *access tail*
|
||||
**phase:** *post-access*
|
||||
|
||||
Same as [access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua), except the code to be executed is in the file
|
||||
specified by `<path-lua-script>`.
|
||||
|
@ -608,7 +625,7 @@ header_filter_by_lua
|
|||
|
||||
**context:** *http, server, location, location if*
|
||||
|
||||
**phase:** *output header filter*
|
||||
**phase:** *output-header-filter*
|
||||
|
||||
Use Lua defined in `<lua-script-str>` to define an output header filter. For now, the following Nginx Lua APIs are disabled in this context:
|
||||
|
||||
|
@ -618,6 +635,7 @@ Use Lua defined in `<lua-script-str>` to define an output header filter. For now
|
|||
|
||||
Here's a small example of overriding a response header (or adding if it does not exist) in our Lua header filter:
|
||||
|
||||
|
||||
location / {
|
||||
proxy_pass http://mybackend;
|
||||
header_filter_by_lua 'ngx.header.Foo = "blah"';
|
||||
|
@ -633,7 +651,7 @@ header_filter_by_lua_file
|
|||
|
||||
**context:** *http, server, location, location if*
|
||||
|
||||
**phase:** *output header filter*
|
||||
**phase:** *output-header-filter*
|
||||
|
||||
Use Lua code defined in a separate file specified by `<path-to-lua-script-file>` to define an output header filter.
|
||||
|
||||
|
@ -664,6 +682,8 @@ the request body won't be read until the content handler's Lua code is
|
|||
about to run (i.e., the request body will be read at the
|
||||
content phase).
|
||||
|
||||
You're recommended to use the [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) function and [ngx.req.discard_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.discard_body) for finer control over the request body reading process though.
|
||||
|
||||
The same applies to [access_by_lua](http://wiki.nginx.org/HttpLuaModule#access_by_lua) and [access_by_lua_file](http://wiki.nginx.org/HttpLuaModule#access_by_lua_file).
|
||||
|
||||
Nginx API for Lua
|
||||
|
@ -740,6 +760,7 @@ ngx.var.VARIABLE
|
|||
Note that you can only write to nginx variables that are already defined.
|
||||
For example:
|
||||
|
||||
|
||||
location /foo {
|
||||
set $my_var ''; # this line is required to create $my_var at config time
|
||||
content_by_lua '
|
||||
|
@ -748,6 +769,7 @@ For example:
|
|||
';
|
||||
}
|
||||
|
||||
|
||||
That is, nginx variables cannot be created on-the-fly.
|
||||
|
||||
Some special nginx variables like `$args` and `$limit_rate` can be assigned a value,
|
||||
|
@ -766,6 +788,7 @@ Core constants
|
|||
ngx.AGAIN (-2)
|
||||
ngx.DONE (-4)
|
||||
|
||||
|
||||
They take the same values of `NGX_OK`, `NGX_AGAIN`, `NGX_DONE`, `NGX_ERROR`, and etc. But now
|
||||
only [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) only take two of these values, i.e., `NGX_OK` and `NGX_ERROR`.
|
||||
|
||||
|
@ -787,6 +810,7 @@ HTTP status constants
|
|||
---------------------
|
||||
**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua**
|
||||
|
||||
|
||||
value = ngx.HTTP_OK (200)
|
||||
value = ngx.HTTP_CREATED (201)
|
||||
value = ngx.HTTP_SPECIAL_RESPONSE (300)
|
||||
|
@ -801,6 +825,7 @@ HTTP status constants
|
|||
value = ngx.HTTP_NOT_ALLOWED (405)
|
||||
value = ngx.HTTP_GONE (410)
|
||||
value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)
|
||||
value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)
|
||||
value = ngx.HTTP_SERVICE_UNAVAILABLE (503)
|
||||
|
||||
|
||||
|
@ -808,6 +833,7 @@ Nginx log level constants
|
|||
-------------------------
|
||||
**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua**
|
||||
|
||||
|
||||
ngx.STDERR
|
||||
ngx.EMERG
|
||||
ngx.ALERT
|
||||
|
@ -831,8 +857,10 @@ Emit args concatenated to nginx's `error.log` file, with log level `ngx.NOTICE`
|
|||
|
||||
It's equivalent to
|
||||
|
||||
|
||||
ngx.log(ngx.NOTICE, 'lua print: ', a, b, ...)
|
||||
|
||||
|
||||
Lua `nil` arguments are accepted and result in literal `"nil"`, and Lua booleans result in `"true"` or `"false"`.
|
||||
|
||||
ngx.ctx
|
||||
|
@ -843,6 +871,7 @@ This table can be used to store per-request context data for Lua programmers.
|
|||
|
||||
This table has a liftime identical to the current request (just like Nginx variables). Consider the following example,
|
||||
|
||||
|
||||
location /test {
|
||||
rewrite_by_lua '
|
||||
ngx.say("foo = ", ngx.ctx.foo)
|
||||
|
@ -856,15 +885,19 @@ This table has a liftime identical to the current request (just like Nginx varia
|
|||
';
|
||||
}
|
||||
|
||||
|
||||
Then `GET /test` will yield the output
|
||||
|
||||
|
||||
foo = nil
|
||||
79
|
||||
|
||||
|
||||
That is, the `ngx.ctx.foo` entry persists across the rewrite, access, and content phases of a request.
|
||||
|
||||
Also, every request has its own copy, include subrequests, for example:
|
||||
|
||||
|
||||
location /sub {
|
||||
content_by_lua '
|
||||
ngx.say("sub pre: ", ngx.ctx.blah)
|
||||
|
@ -883,17 +916,21 @@ Also, every request has its own copy, include subrequests, for example:
|
|||
';
|
||||
}
|
||||
|
||||
|
||||
Then `GET /main` will give the output
|
||||
|
||||
|
||||
main pre: 73
|
||||
sub pre: nil
|
||||
sub post: 32
|
||||
main post: 73
|
||||
|
||||
|
||||
We can see that modification of the `ngx.ctx.blah` entry in the subrequest does not affect the one in its parent request. They do have two separate versions of `ngx.ctx.blah` per se.
|
||||
|
||||
Internal redirection will destroy the original request's `ngx.ctx` data (if any) and the new request will have an emptied `ngx.ctx` table. For instance,
|
||||
|
||||
|
||||
location /new {
|
||||
content_by_lua '
|
||||
ngx.say(ngx.ctx.foo)
|
||||
|
@ -907,16 +944,20 @@ Internal redirection will destroy the original request's `ngx.ctx` data (if any)
|
|||
';
|
||||
}
|
||||
|
||||
|
||||
Then `GET /orig` will give you
|
||||
|
||||
|
||||
nil
|
||||
|
||||
|
||||
rather than the original `"hello"` value.
|
||||
|
||||
Arbitrary data values can be inserted into this "matic" table, including Lua closures and nested tables. You can also register your own meta methods with it.
|
||||
|
||||
Overriding `ngx.ctx` with a new Lua table is also supported, for example,
|
||||
|
||||
|
||||
ngx.ctx = { foo = 32, bar = 54 }
|
||||
|
||||
|
||||
|
@ -937,8 +978,10 @@ Subrequests are completely different from HTTP 301/302 redirection (via [ngx.red
|
|||
|
||||
Here's a basic example:
|
||||
|
||||
|
||||
res = ngx.location.capture(uri)
|
||||
|
||||
|
||||
Returns a Lua table with three slots (`res.status`, `res.header`, and `res.body`).
|
||||
|
||||
`res.header` holds all the response headers of the
|
||||
|
@ -947,17 +990,21 @@ the value is a Lua (array) table that holds all the values in the order that
|
|||
they appear. For instance, if the subrequest response headers contains the following
|
||||
lines:
|
||||
|
||||
|
||||
Set-Cookie: a=3
|
||||
Set-Cookie: foo=bar
|
||||
Set-Cookie: baz=blah
|
||||
|
||||
|
||||
Then `res.header["Set-Cookie"]` will be evaluted to the table value
|
||||
`{"a=3", "foo=bar", "baz=blah"}`.
|
||||
|
||||
URI query strings can be concatenated to URI itself, for instance,
|
||||
|
||||
|
||||
res = ngx.location.capture('/foo/bar?a=3&b=4')
|
||||
|
||||
|
||||
Named locations like `@foo` are not allowed due to a limitation in
|
||||
the nginx core. Use normal locations combined with the `internal` directive to
|
||||
prepare internal-only locations.
|
||||
|
@ -968,11 +1015,13 @@ argument, which support various options like
|
|||
Issuing a POST subrequest, for example,
|
||||
can be done as follows
|
||||
|
||||
|
||||
res = ngx.location.capture(
|
||||
'/foo/bar',
|
||||
{ method = ngx.HTTP_POST, body = 'hello, world' }
|
||||
)
|
||||
|
||||
|
||||
See HTTP method constants methods other than POST.
|
||||
The `method` option is `ngx.HTTP_GET` by default.
|
||||
|
||||
|
@ -986,24 +1035,30 @@ care. So, by default, the option is set to `false`.
|
|||
|
||||
The `args` option can specify extra url arguments, for instance,
|
||||
|
||||
|
||||
ngx.location.capture('/foo?a=1',
|
||||
{ args = { b = 3, c = ':' } }
|
||||
)
|
||||
|
||||
|
||||
is equivalent to
|
||||
|
||||
|
||||
ngx.location.capture('/foo?a=1&b=3&c=%3a')
|
||||
|
||||
|
||||
that is, this method will automatically escape argument keys and values according to URI rules and
|
||||
concatenating them together into a complete query string. Because it's all done in hand-written C,
|
||||
it should be faster than your own Lua code.
|
||||
|
||||
The `args` option can also take plain query string:
|
||||
|
||||
|
||||
ngx.location.capture('/foo?a=1',
|
||||
{ args = 'b=3&c=%3a' } }
|
||||
)
|
||||
|
||||
|
||||
This is functionally identical to the previous examples.
|
||||
|
||||
Note that, by default, subrequests issued by [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) inherit all the
|
||||
|
@ -1023,6 +1078,7 @@ Just like [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.locatio
|
|||
|
||||
This function issue several parallel subrequests specified by the input table, and returns their results in the same order. For example,
|
||||
|
||||
|
||||
res1, res2, res3 = ngx.location.capture_multi{
|
||||
{ "/foo", { args = "a=3&b=4" } },
|
||||
{ "/bar" },
|
||||
|
@ -1037,12 +1093,14 @@ This function issue several parallel subrequests specified by the input table, a
|
|||
...
|
||||
end
|
||||
|
||||
|
||||
This function will not return until all the subrequests terminate.
|
||||
The total latency is the longest latency of the subrequests, instead of their sum.
|
||||
|
||||
When you don't know inadvance how many subrequests you want to issue,
|
||||
you can use Lua tables for both requests and responses. For instance,
|
||||
|
||||
|
||||
-- construct the requests table
|
||||
local reqs = {}
|
||||
table.insert(reqs, { "/mysql" })
|
||||
|
@ -1058,9 +1116,11 @@ you can use Lua tables for both requests and responses. For instance,
|
|||
-- process the response table "resp"
|
||||
end
|
||||
|
||||
|
||||
The [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) function is just a special form
|
||||
of this function. Logically speaking, the [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) can be implemented like this
|
||||
|
||||
|
||||
ngx.location.capture =
|
||||
function (uri, args)
|
||||
return ngx.location.capture_multi({ {uri, args} })
|
||||
|
@ -1074,6 +1134,7 @@ ngx.status
|
|||
Read and write the current request's response status. This should be called
|
||||
before sending out the response headers.
|
||||
|
||||
|
||||
ngx.status = ngx.HTTP_CREATED
|
||||
status = ngx.status
|
||||
|
||||
|
@ -1176,6 +1237,115 @@ Note that `ngx.header` is not a normal Lua table so you cannot iterate through i
|
|||
|
||||
For reading *request* headers, use the [ngx.req.get_headers](http://wiki.nginx.org/HttpLuaModule#ngx.req.get_headers) function instead.
|
||||
|
||||
ngx.req.set_uri
|
||||
---------------
|
||||
**syntax:** *ngx.req.set_uri(uri, jump?)*
|
||||
|
||||
**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua**
|
||||
|
||||
Rewrite the current request's (parsed) URI by the `uri` argument. The `uri` argument must be a Lua string and cannot be of zero length, or a Lua exception will be thrown.
|
||||
|
||||
The optional boolean `jump` argument can trigger location rematch (or location jump) as [HttpRewriteModule](http://wiki.nginx.org/HttpRewriteModule)'s [rewrite](http://wiki.nginx.org/HttpRewriteModule#rewrite) directive, that is, when `jump` is `true` (default to `false`), this function will never return and it will tell Nginx to try re-searching locations with the new URI value at the later `post-rewrite` phase and jumping to the new location. Location jump will not be triggered otherwise, and only the current request's URI will be modified, which is also the default behavior. This function will return but with no returned values when the `jump` argument is `false` or absent altogether.
|
||||
|
||||
For example, the following nginx config snippet
|
||||
|
||||
|
||||
rewrite ^ /foo last;
|
||||
|
||||
|
||||
can be coded in Lua like this:
|
||||
|
||||
|
||||
ngx.req.set_uri("/foo", true)
|
||||
|
||||
|
||||
Similarly, Nginx config
|
||||
|
||||
|
||||
rewrite ^ /foo break;
|
||||
|
||||
|
||||
can be coded in Lua as
|
||||
|
||||
|
||||
ngx.req.set_uri("/foo", false)
|
||||
|
||||
|
||||
or equivalently,
|
||||
|
||||
|
||||
ngx.req.set_uri("/foo")
|
||||
|
||||
|
||||
The `jump` can only be set to `true` in [rewrite_by_lua](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua) and [rewrite_by_lua_file](http://wiki.nginx.org/HttpLuaModule#rewrite_by_lua_file). Use of jump in other contexts is prohibited and will throw out a Lua exception.
|
||||
|
||||
A more sophisticated example involving regex substitutions is as follows
|
||||
|
||||
|
||||
location /test {
|
||||
rewrite_by_lua '
|
||||
local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "$1", "o")
|
||||
ngx.req.set_uri(uri)
|
||||
';
|
||||
proxy_pass http://my_backend;
|
||||
}
|
||||
|
||||
|
||||
which is functionally equivalent to
|
||||
|
||||
|
||||
location /test {
|
||||
rewrite ^/test/(.*) /$1 break;
|
||||
proxy_pass http://my_backend;
|
||||
}
|
||||
|
||||
|
||||
Note that you cannot use this interface to rewrite URI arguments, and you need to use [ngx.req.set_uri_args](http://wiki.nginx.org/HttpLuaModule#ngx.req.set_uri_args) for that. For instance, Nginx config
|
||||
|
||||
|
||||
rewrite ^ /foo?a=3? last;
|
||||
|
||||
|
||||
can be coded as
|
||||
|
||||
|
||||
ngx.req.set_uri_args("a=3")
|
||||
ngx.req.set_uri("/foo", true)
|
||||
|
||||
|
||||
or
|
||||
|
||||
|
||||
ngx.req.set_uri_args({a = 3})
|
||||
ngx.req.set_uri("/foo", true)
|
||||
|
||||
|
||||
This interface was first introduced in the `v0.3.1rc14` release.
|
||||
|
||||
ngx.req.set_uri_args
|
||||
--------------------
|
||||
**syntax:** *ngx.req.set_uri_args(args)*
|
||||
|
||||
**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua**
|
||||
|
||||
Rewrite the current request's URI query arguments by the `args` argument. The `args` argument can be either a Lua string, as in
|
||||
|
||||
|
||||
ngx.req.set_uri_args("a=3&b=hello%20world")
|
||||
|
||||
|
||||
or a Lua table holding the query arguments' key-value pairs, as in
|
||||
|
||||
|
||||
ngx.req.set_uri_args({ a = 3, b = "hello world" })
|
||||
|
||||
|
||||
where in the latter case, this method will automatically escape argument keys and values according to the URI escaping rule.
|
||||
|
||||
This interface was first introduced in the `v0.3.1rc13` release.
|
||||
|
||||
See also [ngx.req.set_uri](http://wiki.nginx.org/HttpLuaModule#ngx.req.set_uri).
|
||||
|
||||
ngx.req.get_uri_args
|
||||
--------------------
|
||||
**syntax:** *args = ngx.req.get_uri_args()*
|
||||
|
@ -1186,6 +1356,7 @@ Returns a Lua table holds all of the current request's request URL query argumen
|
|||
|
||||
Here's an example,
|
||||
|
||||
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
local args = ngx.req.get_uri_args()
|
||||
|
@ -1199,38 +1370,51 @@ Here's an example,
|
|||
';
|
||||
}
|
||||
|
||||
|
||||
Then `GET /test?foo=bar&bar=baz&bar=blah` will yield the response body
|
||||
|
||||
|
||||
foo: bar
|
||||
bar: baz, blah
|
||||
|
||||
|
||||
Multiple occurrences of an argument key will result in a table value holding all of the values for that key in order.
|
||||
|
||||
Keys and values will be automatically unescaped according to URI escaping rules. For example, in the above settings, `GET /test?a%20b=1%61+2` will yield the output
|
||||
|
||||
|
||||
a b: 1a 2
|
||||
|
||||
|
||||
Arguments without the `=<value>` parts are treated as boolean arguments. For example, `GET /test?foo&bar` will yield the outputs
|
||||
|
||||
|
||||
foo: true
|
||||
bar: true
|
||||
|
||||
|
||||
That is, they will take Lua boolean values `true`. However, they're different from arguments taking empty string values. For example, `GET /test?foo=&bar=` will give something like
|
||||
|
||||
|
||||
foo:
|
||||
bar:
|
||||
|
||||
|
||||
Empty key arguments are discarded, for instance, `GET /test?=hello&=world` will yield empty outputs.
|
||||
|
||||
Updating query arguments via the nginx variable `$args` (or `ngx.var.args` in Lua) at runtime are also supported:
|
||||
|
||||
|
||||
ngx.var.args = "a=3&b=42"
|
||||
local args = ngx.req.get_uri_args()
|
||||
|
||||
|
||||
Here the `args` table will always look like
|
||||
|
||||
|
||||
{a = 3, b = 42}
|
||||
|
||||
|
||||
regardless of the actual request query string.
|
||||
|
||||
ngx.req.get_post_args
|
||||
|
@ -1239,14 +1423,14 @@ ngx.req.get_post_args
|
|||
|
||||
**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua**
|
||||
|
||||
Returns a Lua table holds all of the current request's POST query arguments. It's required to turn on the [lua_need_request_body](http://wiki.nginx.org/HttpLuaModule#lua_need_request_body) directive, or a Lua exception will be thrown.
|
||||
Returns a Lua table holds all of the current request's POST query arguments. It's required to read the request body first by calling [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) or to turn on the [lua_need_request_body](http://wiki.nginx.org/HttpLuaModule#lua_need_request_body) directive, or a Lua exception will be thrown.
|
||||
|
||||
Here's an example,
|
||||
|
||||
|
||||
location = /test {
|
||||
lua_need_request_body on;
|
||||
content_by_lua '
|
||||
local args = ngx.req.get_post_args()
|
||||
ngx.req.read_body()
|
||||
for key, val in pairs(args) do
|
||||
if type(val) == "table" then
|
||||
ngx.say(key, ": ", table.concat(val, ", "))
|
||||
|
@ -1257,37 +1441,50 @@ Here's an example,
|
|||
';
|
||||
}
|
||||
|
||||
|
||||
Then
|
||||
|
||||
|
||||
# Post request with the body 'foo=bar&bar=baz&bar=blah'
|
||||
$ curl --data 'foo=bar&bar=baz&bar=blah' localhost/test
|
||||
|
||||
|
||||
will yield the response body like
|
||||
|
||||
|
||||
foo: bar
|
||||
bar: baz, blah
|
||||
|
||||
|
||||
Multiple occurrences of an argument key will result in a table value holding all of the values for that key in order.
|
||||
|
||||
Keys and values will be automatically unescaped according to URI escaping rules. For example, in the above settings,
|
||||
|
||||
|
||||
# POST request with body 'a%20b=1%61+2'
|
||||
$ curl -d 'a%20b=1%61+2' localhost/test
|
||||
|
||||
|
||||
will yield the output
|
||||
|
||||
|
||||
a b: 1a 2
|
||||
|
||||
|
||||
Arguments without the `=<value>` parts are treated as boolean arguments. For example, `GET /test?foo&bar` will yield the outputs
|
||||
|
||||
|
||||
foo: true
|
||||
bar: true
|
||||
|
||||
|
||||
That is, they will take Lua boolean values `true`. However, they're different from arguments taking empty string values. For example, `POST /test` with request body `foo=&bar=` will give something like
|
||||
|
||||
|
||||
foo:
|
||||
bar:
|
||||
|
||||
|
||||
Empty key arguments are discarded, for instance, `POST /test` with body `=hello&=world` will yield empty outputs.
|
||||
|
||||
ngx.req.get_headers
|
||||
|
@ -1300,25 +1497,33 @@ Returns a Lua table holds all of the current request's request headers.
|
|||
|
||||
Here's an example,
|
||||
|
||||
|
||||
local h = ngx.req.get_headers()
|
||||
for k, v in pairs(h) do
|
||||
...
|
||||
end
|
||||
|
||||
|
||||
To read an individual header:
|
||||
|
||||
|
||||
ngx.say("Host: ", ngx.req.get_headers()["Host"])
|
||||
|
||||
|
||||
For multiple instances of request headers like
|
||||
|
||||
|
||||
Foo: foo
|
||||
Foo: bar
|
||||
Foo: baz
|
||||
|
||||
|
||||
the value of `ngx.req.get_headers()["Foo"]` will be a Lua (array) table like this:
|
||||
|
||||
|
||||
{"foo", "bar", "baz"}
|
||||
|
||||
|
||||
Another way to read individual request headers is to use `ngx.var.http_HEADER`, that is, nginx's standard [$http_HEADER](http://wiki.nginx.org/HttpCoreModule#.24http_HEADER) variables.
|
||||
|
||||
ngx.req.set_header
|
||||
|
@ -1332,29 +1537,169 @@ None of the current request's subrequests will be affected.
|
|||
|
||||
Here's an example of setting the `Content-Length` header:
|
||||
|
||||
|
||||
ngx.req.set_header("Content-Type", "text/css")
|
||||
|
||||
|
||||
The `header_value` can take an array list of values,
|
||||
for example,
|
||||
|
||||
|
||||
ngx.req.set_header("Foo", {"a", "abc"})
|
||||
|
||||
|
||||
will produce two new request headers:
|
||||
|
||||
|
||||
Foo: a
|
||||
Foo: abc
|
||||
|
||||
|
||||
and old `Foo` headers will be overridden if there's any.
|
||||
|
||||
When the `header_value` argument is `nil`, the request header will be removed. So
|
||||
|
||||
|
||||
ngx.req.set_header("X-Foo", nil)
|
||||
|
||||
|
||||
is equivalent to
|
||||
|
||||
|
||||
ngx.req.clear_header("X-Foo")
|
||||
|
||||
|
||||
ngx.req.read_body
|
||||
-----------------
|
||||
**syntax:** *ngx.req.read_body()*
|
||||
|
||||
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua**
|
||||
|
||||
Read the client request body synchronously but still non-blockingly.
|
||||
|
||||
If the request body is already read previously by turning on [lua_need_request_body](http://wiki.nginx.org/HttpLuaModule#lua_need_request_body) or by using other modules, then this function is a no-op and returns immediately.
|
||||
|
||||
If the request body has already been explicitly discarded, either by this module's [ngx.req.discard_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.discard_body) or other modules, this function is a no-op and returns immediately.
|
||||
|
||||
In case of errors, like connection errors while reading the data, this method will throw out a Lua exception *or* terminate the current request with the 500 status code immediately.
|
||||
|
||||
You can later either retrieve the request body data via [ngx.req.get_body_data](http://wiki.nginx.org/HttpLuaModule#ngx.req.get_body_data) or retrieve the temporary file name for the body data cached to disk via [ngx.req.get_body_file](http://wiki.nginx.org/HttpLuaModule#ngx.req.get_body_file), depending on
|
||||
|
||||
1. whether the current request body is already exceeding your [client_body_buffer_size](http://wiki.nginx.org/HttpCoreModule#client_body_buffer_size),
|
||||
1. and whether you have turned on [client_body_in_file_only](http://wiki.nginx.org/HttpCoreModule#client_body_in_file_only).
|
||||
|
||||
In case that you do not want to read the request body and the current request may have a request body, then it's crucial to use the [ngx.req.discard_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.discard_body) function to explicitly discard the request body, or you'll break HTTP 1.1 keepalive and HTTP 1.1 pipelining.
|
||||
|
||||
Here's a small example:
|
||||
|
||||
|
||||
ngx.req.read_body()
|
||||
local args = ngx.req.get_post_args()
|
||||
|
||||
|
||||
This function was first introduced in the `v0.3.1rc17` release.
|
||||
|
||||
ngx.req.discard_body
|
||||
--------------------
|
||||
**syntax:** *ngx.req.discard_body()*
|
||||
|
||||
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua**
|
||||
|
||||
Explicitly discard the request body, i.e., read the data on the connection and throw it away immediately. Please note that, simply ignoring request body is not the right way to discard it, you need to call this function, or you'll break things under HTTP 1.1 keepalive or HTTP 1.1 pipelining.
|
||||
|
||||
This function is an asynchronous call and returns immediately.
|
||||
|
||||
If the request body has already been read, this function does nothing and returns immediately.
|
||||
|
||||
This function was first introduced in the `v0.3.1rc17` release.
|
||||
|
||||
See also [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body).
|
||||
|
||||
ngx.req.get_body_data
|
||||
---------------------
|
||||
**syntax:** *data = ngx.req.get_body_data()*
|
||||
|
||||
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua**
|
||||
|
||||
Retrieves the in-memory request body data. It returns a Lua string rather than a Lua table holding all the parsed query arguments. If you want the latter, use [ngx.req.get_post_args](http://wiki.nginx.org/HttpLuaModule#ngx.req.get_post_args) instead.
|
||||
|
||||
This function returns `nil` if
|
||||
1. the request body has not been read,
|
||||
1. the request body has been read into disk temporary files,
|
||||
1. or the request body has zero size.
|
||||
|
||||
If the request body has not been read yet, call [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) first (or turned on [lua_need_request_body](http://wiki.nginx.org/HttpLuaModule#lua_need_request_body) to force this module to read the request body automatically, but this is not recommended).
|
||||
|
||||
If the request body has been read into disk files, try calling the [ngx.req.get_body_file](http://wiki.nginx.org/HttpLuaModule#ngx.req.get_body_file) function instead.
|
||||
|
||||
In case that you want to enforce in-memory request bodies, try setting [client_body_buffer_size](http://wiki.nginx.org/HttpCoreModule#client_body_buffer_size) to the same size value in [client_max_body_size](http://wiki.nginx.org/HttpCoreModule#client_max_body_size).
|
||||
|
||||
Note that calling this function instead of using `ngx.var.request_body` or `ngx.var.echo_request-body` is more efficient because it can save one dynamic memory allocation and one data copy.
|
||||
|
||||
This function was first introduced in the `v0.3.1rc17` release.
|
||||
|
||||
See also [ngx.req.get_body_file](http://wiki.nginx.org/HttpLuaModule#ngx.req.get_body_file).
|
||||
|
||||
ngx.req.get_body_file
|
||||
---------------------
|
||||
**syntax:** *file_name = ngx.req.get_body_file()*
|
||||
|
||||
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua**
|
||||
|
||||
Retrieves the file name for the in-file request body data. Returns `nil` if the request body has not been read or has been read into memory.
|
||||
|
||||
The returned file is read only and is usually cleaned up automatically by Nginx's memory pool. It should not be modified, renamed, or removed by your own Lua code.
|
||||
|
||||
If the request body has not been read yet, call [ngx.req.read_body](http://wiki.nginx.org/HttpLuaModule#ngx.req.read_body) first (or turned on [lua_need_request_body](http://wiki.nginx.org/HttpLuaModule#lua_need_request_body) to force this module to read the request body automatically, but this is not recommended).
|
||||
|
||||
If the request body has been read into memory, try calling the [ngx.req.get_body_data](http://wiki.nginx.org/HttpLuaModule#ngx.req.get_body_data) function instead.
|
||||
|
||||
In case that you want to enforce in-file request bodies, try turning on [client_body_in_file_only](http://wiki.nginx.org/HttpCoreModule#client_body_in_file_only).
|
||||
|
||||
This function was first introduced in the `v0.3.1rc17` release.
|
||||
|
||||
See also [ngx.req.get_body_data](http://wiki.nginx.org/HttpLuaModule#ngx.req.get_body_data).
|
||||
|
||||
ngx.req.set_body_data
|
||||
---------------------
|
||||
**syntax:** *ngx.req.set_body_data(data)*
|
||||
|
||||
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua**
|
||||
|
||||
Set the current request's request body using the in-memory data specified by the `data` argument.
|
||||
|
||||
If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively.
|
||||
|
||||
This function requires patching the Nginx core to function properly because the Nginx core does not allow modifying request bodies by the current design. Here is a patch for Nginx 1.0.8: [nginx-1.0.8-allow_request_body_updating.patch](https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.0.8-allow_request_body_updating.patch), and this patch should be applied cleanly to other releases of Nginx as well.
|
||||
|
||||
If you're using [ngx_openresty](http://openresty.org/) 1.0.8.17+, then you've already had this patch applied.
|
||||
|
||||
This function was first introduced in the `v0.3.1rc18` release.
|
||||
|
||||
See also [ngx.req.set_body_file](http://wiki.nginx.org/HttpLuaModule#ngx.req.set_body_file).
|
||||
|
||||
ngx.req.set_body_file
|
||||
---------------------
|
||||
**syntax:** *ngx.req.set_body_file(file_name, auto_clean?)*
|
||||
|
||||
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua**
|
||||
|
||||
Set the current request's request body using the in-file data specified by the `file_name` argument.
|
||||
|
||||
If the optional `auto_clean` argument is given a `true` value, then this file will be automatically removed at request completion or the next time this function or [ngx.req.set_body_data](http://wiki.nginx.org/HttpLuaModule#ngx.req.set_body_data) are called in the same request. The `auto_clean` is default to `false`.
|
||||
|
||||
You must ensure that the file specified by the `file_name` argument exists and is readable by an Nginx worker process by setting its permission properly. Otherwise a Lua exception will be thrown.
|
||||
|
||||
If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively.
|
||||
|
||||
This function requires patching the Nginx core to function properly because the Nginx core does not allow modifying request bodies by the current design. Here is a patch for Nginx 1.0.8: [nginx-1.0.8-allow_request_body_updating.patch](https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.0.8-allow_request_body_updating.patch), and this patch should be applied cleanly to other releases of Nginx as well.
|
||||
|
||||
If you're using [ngx_openresty](http://openresty.org/) 1.0.8.17+, then you've already had this patch applied.
|
||||
|
||||
This function was first introduced in the `v0.3.1rc18` release.
|
||||
|
||||
See also [ngx.req.set_body_data](http://wiki.nginx.org/HttpLuaModule#ngx.req.set_body_data).
|
||||
|
||||
ngx.req.clear_header
|
||||
--------------------
|
||||
**syntax:** *ngx.req.clear_header(header_name)*
|
||||
|
@ -1448,7 +1793,7 @@ This method is very much like the [rewrite](http://wiki.nginx.org/HttpRewriteMod
|
|||
[HttpRewriteModule](http://wiki.nginx.org/HttpRewriteModule), for example, this `nginx.conf` snippet
|
||||
|
||||
|
||||
rewrite ^ /foo redirect; # nginx config
|
||||
rewrite ^ /foo? redirect; # nginx config
|
||||
|
||||
|
||||
is equivalent to the following Lua code
|
||||
|
@ -1460,7 +1805,7 @@ is equivalent to the following Lua code
|
|||
while
|
||||
|
||||
|
||||
rewrite ^ /foo permanent; # nginx config
|
||||
rewrite ^ /foo? permanent; # nginx config
|
||||
|
||||
|
||||
is equivalent to
|
||||
|
@ -1469,6 +1814,12 @@ is equivalent to
|
|||
return ngx.redirect('/foo', ngx.HTTP_MOVED_PERMANENTLY) -- Lua code
|
||||
|
||||
|
||||
URI arguments can be specified as well, for example:
|
||||
|
||||
|
||||
return ngx.redirect('/foo?a=3&b=4')
|
||||
|
||||
|
||||
ngx.send_headers
|
||||
----------------
|
||||
**syntax:** *ngx.send_headers()*
|
||||
|
@ -1585,6 +1936,12 @@ The effect in action:
|
|||
This is our own content
|
||||
|
||||
|
||||
Number literals can be used directly as the argument, for instance,
|
||||
|
||||
|
||||
ngx.exit(501)
|
||||
|
||||
|
||||
ngx.eof
|
||||
-------
|
||||
**syntax:** *ngx.eof()*
|
||||
|
@ -1699,9 +2056,11 @@ ngx.cookie_time
|
|||
|
||||
Returns a formated string can be used as the cookie expiration time. The parameter `sec` is the timestamp in seconds (like those returned from [ngx.time](http://wiki.nginx.org/HttpLuaModule#ngx.time)).
|
||||
|
||||
|
||||
ngx.say(ngx.cookie_time(1290079655))
|
||||
-- yields "Thu, 18-Nov-10 11:27:35 GMT"
|
||||
|
||||
|
||||
ngx.http_time
|
||||
-------------
|
||||
**syntax:** *str = ngx.http_time(sec)*
|
||||
|
@ -1710,9 +2069,11 @@ ngx.http_time
|
|||
|
||||
Returns a formated string can be used as the http header time (for example, being used in `Last-Modified` header). The parameter `sec` is the timestamp in seconds (like those returned from [ngx.time](http://wiki.nginx.org/HttpLuaModule#ngx.time)).
|
||||
|
||||
|
||||
ngx.say(ngx.http_time(1290079655))
|
||||
-- yields "Thu, 18 Nov 10 11:27:35 GMT"
|
||||
|
||||
|
||||
ngx.parse_http_time
|
||||
-------------------
|
||||
**syntax:** *sec = ngx.parse_http_time(str)*
|
||||
|
@ -1721,11 +2082,13 @@ ngx.parse_http_time
|
|||
|
||||
Parse the http time string (as returned by [ngx.http_time](http://wiki.nginx.org/HttpLuaModule#ngx.http_time)) into seconds. Returns the seconds or `nil` if the input string is in bad forms.
|
||||
|
||||
|
||||
local time = ngx.parse_http_time("Thu, 18 Nov 10 11:27:35 GMT")
|
||||
if time == nil then
|
||||
...
|
||||
end
|
||||
|
||||
|
||||
ngx.is_subrequest
|
||||
-----------------
|
||||
**syntax:** *value = ngx.is_subrequest*
|
||||
|
@ -2087,13 +2450,14 @@ The installation steps are usually as simple as `./configure && make && make ins
|
|||
Alternatively, you can compile this module with nginx core's source by hand:
|
||||
|
||||
1. Install Lua or LuaJIT into your system. At least Lua 5.1 is required. Lua can be obtained freely from its project [homepage](http://www.lua.org/). For Ubuntu/Debian users, just install the liblua5.1-0-dev package (or something like that).
|
||||
1. Download the latest version of the release tarball of the ngx_devel_kit (NDK) module from lua-nginx-module [file list](http://github.com/simpl/ngx_devel_kit/downloads).
|
||||
1. Download the latest version of the release tarball of this module from lua-nginx-module [file list](http://github.com/chaoslawful/lua-nginx-module/downloads).
|
||||
1. Download the latest version of the release tarball of the ngx_devel_kit (NDK) module from lua-nginx-module [file list](http://github.com/simpl/ngx_devel_kit/tags).
|
||||
1. Download the latest version of the release tarball of this module from lua-nginx-module [file list](http://github.com/chaoslawful/lua-nginx-module/tags).
|
||||
1. Grab the nginx source code from [nginx.org](http://nginx.org/), for example, the version 1.0.5 (see nginx compatibility), and then build the source with this module:
|
||||
|
||||
$ wget 'http://nginx.org/download/nginx-1.0.5.tar.gz'
|
||||
$ tar -xzvf nginx-1.0.5.tar.gz
|
||||
$ cd nginx-1.0.5/
|
||||
|
||||
wget 'http://nginx.org/download/nginx-1.0.5.tar.gz'
|
||||
tar -xzvf nginx-1.0.5.tar.gz
|
||||
cd nginx-1.0.5/
|
||||
|
||||
# tell nginx's build system where to find lua:
|
||||
export LUA_LIB=/path/to/lua/lib
|
||||
|
@ -2104,12 +2468,12 @@ Alternatively, you can compile this module with nginx core's source by hand:
|
|||
# export LUAJIT_INC=/path/to/luajit/include/luajit-2.0
|
||||
|
||||
# Here we assume you would install you nginx under /opt/nginx/.
|
||||
$ ./configure --prefix=/opt/nginx \
|
||||
./configure --prefix=/opt/nginx \
|
||||
--add-module=/path/to/ngx_devel_kit \
|
||||
--add-module=/path/to/lua-nginx-module
|
||||
|
||||
$ make -j2
|
||||
$ make install
|
||||
make -j2
|
||||
make install
|
||||
|
||||
|
||||
Compatibility
|
||||
|
@ -2187,24 +2551,28 @@ filtering chain affects a lot. The correct configure adding order is:
|
|||
|
||||
TODO
|
||||
====
|
||||
|
||||
* Add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) and ngx.location.capture_multi` methods, to allow micro performance tuning on the user side.
|
||||
* Add directives to run lua codes when nginx stops/reloads.
|
||||
* Deal with TCP 3-second delay problem under great connection harness.
|
||||
* add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) and ngx.location.capture_multi` methods, to allow micro performance tuning on the user side.
|
||||
* add directives to run lua codes when nginx stops/reloads.
|
||||
* deal with TCP 3-second delay problem under great connection harness.
|
||||
* add options to [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) and [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi) in order to share and copy a particular set of nginx variables with subrequests, specified by the user.
|
||||
* add an option to [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) and [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi) so as to specify the [ngx.ctx](http://wiki.nginx.org/HttpLuaModule#ngx.ctx) table for subrequests.
|
||||
* expose nginx's shared memory facility to the Lua land.
|
||||
* add support for multi-value arguments to [[#ngx.req.set_uri_args]] if its `args` argument is a Lua table.
|
||||
|
||||
Future Plan
|
||||
===========
|
||||
|
||||
* Add the `lua_require` directive to load module into main thread's globals.
|
||||
* Add the "cosocket" mechamism that will emulate a common set of Lua socket API that will give you totally transparently non-blocking capability out of the box by means of a completely new upstream layer atop the nginx event model and no nginx subrequest overheads.
|
||||
* Add Lua code automatic time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks.
|
||||
* Make set_by_lua using the same mechanism as content_by_lua.
|
||||
* add the `lua_require` directive to load module into main thread's globals.
|
||||
* add the "cosocket" mechamism that will emulate a common set of Lua socket API that will give you totally transparently non-blocking capability out of the box by means of a completely new upstream layer atop the nginx event model and no nginx subrequest overheads.
|
||||
* add Lua code automatic time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks.
|
||||
* make set_by_lua using the same mechanism as content_by_lua.
|
||||
* add coroutine API back to the Lua land.
|
||||
|
||||
Known Issues
|
||||
============
|
||||
|
||||
* As ngx_lua's predefined Nginx I/O APIs use coroutine yielding/resuming mechanism, the user code should not call any Lua modules that use coroutine API to prevent obfuscating the predefined Nginx APIs like [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) (actually coroutine modules have been masked off in [content_by_lua](http://wiki.nginx.org/HttpLuaModule#content_by_lua) directives and others). This limitation is a little crucial, but don't worry, we're working on an alternative coroutine implementation that can fit into the Nginx event model. When it is done, the user code will be able to use the Lua coroutine mechanism freely as in standard Lua again!
|
||||
* Because the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture), [[#ngx.location.capture_multi|ngx.location.capture_multi], [ngx.redirect](http://wiki.nginx.org/HttpLuaModule#ngx.redirect), [ngx.exec](http://wiki.nginx.org/HttpLuaModule#ngx.exec), and [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) when the standard Lua 5.1 interpreter is used; you'll get the error `attempt to yield across metamethod/C-call boundary`. To fix this, please use LuaJIT 2.0 instead, because LuaJIT 2.0 supports a fully resume-able VM.
|
||||
* Because the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture), [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi), [ngx.redirect](http://wiki.nginx.org/HttpLuaModule#ngx.redirect), [ngx.exec](http://wiki.nginx.org/HttpLuaModule#ngx.exec), and [ngx.exit](http://wiki.nginx.org/HttpLuaModule#ngx.exit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) when the standard Lua 5.1 interpreter is used; you'll get the error `attempt to yield across metamethod/C-call boundary`. To fix this, please use LuaJIT 2.0 instead, because LuaJIT 2.0 supports a fully resume-able VM.
|
||||
* The [ngx.location.capture](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture) and [ngx.location.capture_multi](http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi) Lua methods cannot capture locations configured by [HttpEchoModule](http://wiki.nginx.org/HttpEchoModule)'s [echo_location](http://wiki.nginx.org/HttpEchoModule#echo_location), [echo_location_async](http://wiki.nginx.org/HttpEchoModule#echo_location_async), [echo_subrequest](http://wiki.nginx.org/HttpEchoModule#echo_subrequest), or [echo_subrequest_async](http://wiki.nginx.org/HttpEchoModule#echo_subrequest_async) directives. This won't be fixed in the future due to technical problems.
|
||||
* **WATCH OUT: Globals WON'T persist between requests**, because of the one-coroutine-per-request isolation design. Especially watch yourself when using `require()` to import modules, and use this form:
|
||||
|
||||
|
|
4
config
4
config
|
@ -140,8 +140,8 @@ fi
|
|||
|
||||
ngx_addon_name=ngx_http_lua_module
|
||||
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_lua_module"
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_http_lua_script.c $ngx_addon_dir/src/ngx_http_lua_log.c $ngx_addon_dir/src/ngx_http_lua_subrequest.c $ngx_addon_dir/src/ngx_http_lua_ndk.c $ngx_addon_dir/src/ngx_http_lua_control.c $ngx_addon_dir/src/ngx_http_lua_time.c $ngx_addon_dir/src/ngx_http_lua_misc.c $ngx_addon_dir/src/ngx_http_lua_variable.c $ngx_addon_dir/src/ngx_http_lua_string.c $ngx_addon_dir/src/ngx_http_lua_output.c $ngx_addon_dir/src/ngx_http_lua_headers.c $ngx_addon_dir/src/ngx_http_lua_args.c $ngx_addon_dir/src/ngx_http_lua_ctx.c $ngx_addon_dir/src/ngx_http_lua_regex.c $ngx_addon_dir/src/ngx_http_lua_module.c $ngx_addon_dir/src/ngx_http_lua_headers_out.c $ngx_addon_dir/src/ngx_http_lua_headers_in.c $ngx_addon_dir/src/ngx_http_lua_directive.c $ngx_addon_dir/src/ngx_http_lua_consts.c $ngx_addon_dir/src/ngx_http_lua_exception.c $ngx_addon_dir/src/ngx_http_lua_util.c $ngx_addon_dir/src/ngx_http_lua_cache.c $ngx_addon_dir/src/ngx_http_lua_conf.c $ngx_addon_dir/src/ngx_http_lua_contentby.c $ngx_addon_dir/src/ngx_http_lua_rewriteby.c $ngx_addon_dir/src/ngx_http_lua_accessby.c $ngx_addon_dir/src/ngx_http_lua_setby.c $ngx_addon_dir/src/ngx_http_lua_capturefilter.c $ngx_addon_dir/src/ngx_http_lua_clfactory.c $ngx_addon_dir/src/ngx_http_lua_pcrefix.c $ngx_addon_dir/src/ngx_http_lua_headerfilterby.c $ngx_addon_dir/src/ngx_http_lua_shdict.c"
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/src/ddebug.h $ngx_addon_dir/src/ngx_http_lua_script.h $ngx_addon_dir/src/ngx_http_lua_log.h $ngx_addon_dir/src/ngx_http_lua_subrequest.h $ngx_addon_dir/src/ngx_http_lua_ndk.h $ngx_addon_dir/src/ngx_http_lua_control.h $ngx_addon_dir/src/ngx_http_lua_time.h $ngx_addon_dir/src/ngx_http_lua_string.h $ngx_addon_dir/src/ngx_http_lua_misc.h $ngx_addon_dir/src/ngx_http_lua_variable.h $ngx_addon_dir/src/ngx_http_lua_output.h $ngx_addon_dir/src/ngx_http_lua_headers.h $ngx_addon_dir/src/ngx_http_lua_args.h $ngx_addon_dir/src/ngx_http_lua_ctx.h $ngx_addon_dir/src/ngx_http_lua_regex.h $ngx_addon_dir/src/ngx_http_lua_common.h $ngx_addon_dir/src/ngx_http_lua_directive.h $ngx_addon_dir/src/ngx_http_lua_headers_out.h $ngx_addon_dir/src/ngx_http_lua_headers_in.h $ngx_addon_dir/src/ngx_http_lua_consts.h $ngx_addon_dir/src/ngx_http_lua_exception.h $ngx_addon_dir/src/ngx_http_lua_util.h $ngx_addon_dir/src/ngx_http_lua_cache.h $ngx_addon_dir/src/ngx_http_lua_conf.h $ngx_addon_dir/src/ngx_http_lua_contentby.h $ngx_addon_dir/src/ngx_http_lua_rewriteby.h $ngx_addon_dir/src/ngx_http_lua_accessby.h $ngx_addon_dir/src/ngx_http_lua_setby.h $ngx_addon_dir/src/ngx_http_lua_capturefilter.h $ngx_addon_dir/src/ngx_http_lua_clfactory.h $ngx_addon_dir/src/ngx_http_lua_pcrefix.h $ngx_addon_dir/src/ngx_http_lua_headerfilterby.h $ngx_addon_dir/src/ngx_http_lua_shdict.h"
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_http_lua_script.c $ngx_addon_dir/src/ngx_http_lua_log.c $ngx_addon_dir/src/ngx_http_lua_subrequest.c $ngx_addon_dir/src/ngx_http_lua_ndk.c $ngx_addon_dir/src/ngx_http_lua_control.c $ngx_addon_dir/src/ngx_http_lua_time.c $ngx_addon_dir/src/ngx_http_lua_misc.c $ngx_addon_dir/src/ngx_http_lua_variable.c $ngx_addon_dir/src/ngx_http_lua_string.c $ngx_addon_dir/src/ngx_http_lua_output.c $ngx_addon_dir/src/ngx_http_lua_headers.c $ngx_addon_dir/src/ngx_http_lua_req_body.c $ngx_addon_dir/src/ngx_http_lua_uri.c $ngx_addon_dir/src/ngx_http_lua_args.c $ngx_addon_dir/src/ngx_http_lua_ctx.c $ngx_addon_dir/src/ngx_http_lua_regex.c $ngx_addon_dir/src/ngx_http_lua_module.c $ngx_addon_dir/src/ngx_http_lua_headers_out.c $ngx_addon_dir/src/ngx_http_lua_headers_in.c $ngx_addon_dir/src/ngx_http_lua_directive.c $ngx_addon_dir/src/ngx_http_lua_consts.c $ngx_addon_dir/src/ngx_http_lua_exception.c $ngx_addon_dir/src/ngx_http_lua_util.c $ngx_addon_dir/src/ngx_http_lua_cache.c $ngx_addon_dir/src/ngx_http_lua_conf.c $ngx_addon_dir/src/ngx_http_lua_contentby.c $ngx_addon_dir/src/ngx_http_lua_rewriteby.c $ngx_addon_dir/src/ngx_http_lua_accessby.c $ngx_addon_dir/src/ngx_http_lua_setby.c $ngx_addon_dir/src/ngx_http_lua_capturefilter.c $ngx_addon_dir/src/ngx_http_lua_clfactory.c $ngx_addon_dir/src/ngx_http_lua_pcrefix.c $ngx_addon_dir/src/ngx_http_lua_headerfilterby.c $ngx_addon_dir/src/ngx_http_lua_shdict.c"
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/src/ddebug.h $ngx_addon_dir/src/ngx_http_lua_script.h $ngx_addon_dir/src/ngx_http_lua_log.h $ngx_addon_dir/src/ngx_http_lua_subrequest.h $ngx_addon_dir/src/ngx_http_lua_ndk.h $ngx_addon_dir/src/ngx_http_lua_control.h $ngx_addon_dir/src/ngx_http_lua_time.h $ngx_addon_dir/src/ngx_http_lua_string.h $ngx_addon_dir/src/ngx_http_lua_misc.h $ngx_addon_dir/src/ngx_http_lua_variable.h $ngx_addon_dir/src/ngx_http_lua_output.h $ngx_addon_dir/src/ngx_http_lua_headers.h $ngx_addon_dir/src/ngx_http_lua_uri.h $ngx_addon_dir/src/ngx_http_lua_req_body.h $ngx_addon_dir/src/ngx_http_lua_args.h $ngx_addon_dir/src/ngx_http_lua_ctx.h $ngx_addon_dir/src/ngx_http_lua_regex.h $ngx_addon_dir/src/ngx_http_lua_common.h $ngx_addon_dir/src/ngx_http_lua_directive.h $ngx_addon_dir/src/ngx_http_lua_headers_out.h $ngx_addon_dir/src/ngx_http_lua_headers_in.h $ngx_addon_dir/src/ngx_http_lua_consts.h $ngx_addon_dir/src/ngx_http_lua_exception.h $ngx_addon_dir/src/ngx_http_lua_util.h $ngx_addon_dir/src/ngx_http_lua_cache.h $ngx_addon_dir/src/ngx_http_lua_conf.h $ngx_addon_dir/src/ngx_http_lua_contentby.h $ngx_addon_dir/src/ngx_http_lua_rewriteby.h $ngx_addon_dir/src/ngx_http_lua_accessby.h $ngx_addon_dir/src/ngx_http_lua_setby.h $ngx_addon_dir/src/ngx_http_lua_capturefilter.h $ngx_addon_dir/src/ngx_http_lua_clfactory.h $ngx_addon_dir/src/ngx_http_lua_pcrefix.h $ngx_addon_dir/src/ngx_http_lua_headerfilterby.h $ngx_addon_dir/src/ngx_http_lua_shdict.h"
|
||||
CFLAGS="$CFLAGS -DNDK_SET_VAR"
|
||||
|
||||
ngx_feature="export symbols by default"
|
||||
|
|
|
@ -10,7 +10,7 @@ This module is under active development and is already production ready.
|
|||
|
||||
= Version =
|
||||
|
||||
This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/downloads v0.3.1rc9] released on 9 October 2011.
|
||||
This document describes ngx_lua [https://github.com/chaoslawful/lua-nginx-module/tags v0.3.1rc20] released on 24 October 2011.
|
||||
|
||||
= Synopsis =
|
||||
<geshi lang="nginx">
|
||||
|
@ -298,6 +298,7 @@ anything that may be blocked or time-consuming.
|
|||
Note that [[#set_by_lua|set_by_lua]] can only output a value to a single Nginx variable at
|
||||
a time. But a work-around is also available by means of the [[#ngx.var.VARIABLE|ngx.var.VARIABLE]] interface,
|
||||
for example,
|
||||
|
||||
<geshi lang="nginx">
|
||||
location /foo {
|
||||
set $diff ''; # we have to predefine the $diff variable here
|
||||
|
@ -315,6 +316,7 @@ for example,
|
|||
</geshi>
|
||||
|
||||
This directive can be freely mixed with all the directives of [[HttpRewriteModule]], [[HttpSetMiscModule]], and [[HttpArrayVarModule]]. All of these directives will run in exactly the same order that they are written in the config file. For example,
|
||||
|
||||
<geshi lang="nginx">
|
||||
set $foo 32;
|
||||
set_by_lua $bar 'tonumber(ngx.var.foo) + 1';
|
||||
|
@ -324,11 +326,12 @@ This directive can be freely mixed with all the directives of [[HttpRewriteModul
|
|||
This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] module.
|
||||
|
||||
== set_by_lua_file ==
|
||||
|
||||
'''syntax:''' ''set_by_lua_file $res <path-to-lua-script> [$arg1 $arg2 ...]''
|
||||
|
||||
'''context:''' ''main, server, location, server if, location if''
|
||||
|
||||
'''phase:''' ''rewrite''
|
||||
|
||||
Basically the same as [[#set_by_lua|set_by_lua]], except the code to be executed is in the
|
||||
file specified by <code><path-lua-script></code>.
|
||||
|
||||
|
@ -378,7 +381,7 @@ When the Lua code cache is on (this is the default), the user code is loaded onc
|
|||
|
||||
'''context:''' ''http, server, location, location if''
|
||||
|
||||
'''phase:''' ''rewrite tail''
|
||||
'''phase:''' ''post-rewrite''
|
||||
|
||||
Act as a rewrite phase handler and execute user code specified by <code><lua-script-str></code>
|
||||
for every request. The user code may call predefined APIs to generate response
|
||||
|
@ -475,13 +478,27 @@ Just as any other rewrite phase handlers, [[#rewrite_by_lua|rewrite_by_lua]] als
|
|||
|
||||
Note that calling <code>ngx.exit(ngx.OK)</code> just returning from the current [[#rewrite_by_lua|rewrite_by_lua]] handler, and the nginx request processing control flow will still continue to the content handler. To terminate the current request from within the current [[#rewrite_by_lua|rewrite_by_lua]] handler, calling [[#ngx.exit|ngx.exit]] with status >= 200 (<code>ngx.HTTP_OK</code>) and status < 300 (<code>ngx.HTTP_SPECIAL_RESPONSE</code>) for successful quits and <code>ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)</code> (or its friends) for failures.
|
||||
|
||||
If one uses [[HttpRewriteModule]]'s [[HttpRewriteModule#rewrite|rewrite]] directive to change the URI and initiate location re-lookups (kinda like internal redirections), then [[#rewrite_by_lua|rewrite_by_lua]] and [[#rewrite_by_lua_file|rewrite_by_lua_file]] will be skipped altogether in the current location. For example,
|
||||
|
||||
<geshi lang="nginx">
|
||||
location /foo {
|
||||
rewrite ^ /bar;
|
||||
rewrite_by_lua 'ngx.exit(503)';
|
||||
}
|
||||
location /bar {
|
||||
...
|
||||
}
|
||||
</geshi>
|
||||
|
||||
Here the Lua code <code>ngx.exit(503)</code> will never run while all the Lua code (except access phase handlers) in the <code>/bar</code> location will not be affected anyway. Similarly, <code>rewrite ^ /bar last</code> will also initiate a location re-lookup. If you use the <code>break</code> modifier for the [[HttpRewriteModule#rewrite|rewrite]] directive, however, no location re-lookup will be triggered, and therefore, the rewrite-phase Lua code will still be run as normal.
|
||||
|
||||
== rewrite_by_lua_file ==
|
||||
|
||||
'''syntax:''' ''rewrite_by_lua_file <path-to-lua-script>''
|
||||
|
||||
'''context:''' ''http, server, location, location if''
|
||||
|
||||
'''phase:''' ''rewrite tail''
|
||||
'''phase:''' ''post-rewrite''
|
||||
|
||||
Same as [[#rewrite_by_lua|rewrite_by_lua]], except the code to be executed is in
|
||||
the file specified by <code><path-lua-script></code>.
|
||||
|
@ -501,7 +518,7 @@ Lua code cache by setting [[#lua_code_cache|lua_code_cache]] <code>off</code> in
|
|||
|
||||
'''context:''' ''http, server, location, location if''
|
||||
|
||||
'''phase:''' ''access tail''
|
||||
'''phase:''' ''post-access''
|
||||
|
||||
Act as an access phase handler and execute user code specified by <code><lua-script-str></code> for every request. The user code may call predefined APIs to generate response content.
|
||||
|
||||
|
@ -569,7 +586,7 @@ Note that calling <code>ngx.exit(ngx.OK)</code> just returning from the current
|
|||
|
||||
'''context:''' ''http, server, location, location if''
|
||||
|
||||
'''phase:''' ''access tail''
|
||||
'''phase:''' ''post-access''
|
||||
|
||||
Same as [[#access_by_lua|access_by_lua]], except the code to be executed is in the file
|
||||
specified by <code><path-lua-script></code>.
|
||||
|
@ -589,7 +606,7 @@ Lua code cache by setting [[#lua_code_cache|lua_code_cache]] <code>off</code> in
|
|||
|
||||
'''context:''' ''http, server, location, location if''
|
||||
|
||||
'''phase:''' ''output header filter''
|
||||
'''phase:''' ''output-header-filter''
|
||||
|
||||
Use Lua defined in <code><lua-script-str></code> to define an output header filter. For now, the following Nginx Lua APIs are disabled in this context:
|
||||
|
||||
|
@ -598,6 +615,7 @@ Use Lua defined in <code><lua-script-str></code> to define an output header filt
|
|||
* Subrequest APIs (e.g., [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]])
|
||||
|
||||
Here's a small example of overriding a response header (or adding if it does not exist) in our Lua header filter:
|
||||
|
||||
<geshi lang="nginx">
|
||||
location / {
|
||||
proxy_pass http://mybackend;
|
||||
|
@ -613,7 +631,7 @@ This directive was first introduced in the <code>v0.2.1rc20</code> release.
|
|||
|
||||
'''context:''' ''http, server, location, location if''
|
||||
|
||||
'''phase:''' ''output header filter''
|
||||
'''phase:''' ''output-header-filter''
|
||||
|
||||
Use Lua code defined in a separate file specified by <code><path-to-lua-script-file></code> to define an output header filter.
|
||||
|
||||
|
@ -643,6 +661,8 @@ the request body won't be read until the content handler's Lua code is
|
|||
about to run (i.e., the request body will be read at the
|
||||
content phase).
|
||||
|
||||
You're recommended to use the [[#ngx.req.read_body|ngx.req.read_body]] function and [[#ngx.req.discard_body|ngx.req.discard_body]] for finer control over the request body reading process though.
|
||||
|
||||
The same applies to [[#access_by_lua|access_by_lua]] and [[#access_by_lua_file|access_by_lua_file]].
|
||||
|
||||
= Nginx API for Lua =
|
||||
|
@ -715,6 +735,7 @@ that outputs <code>88</code>, the sum of <code>32</code> and <code>56</code>.
|
|||
</geshi>
|
||||
Note that you can only write to nginx variables that are already defined.
|
||||
For example:
|
||||
|
||||
<geshi lang="nginx">
|
||||
location /foo {
|
||||
set $my_var ''; # this line is required to create $my_var at config time
|
||||
|
@ -724,6 +745,7 @@ For example:
|
|||
';
|
||||
}
|
||||
</geshi>
|
||||
|
||||
That is, nginx variables cannot be created on-the-fly.
|
||||
|
||||
Some special nginx variables like <code>$args</code> and <code>$limit_rate</code> can be assigned a value,
|
||||
|
@ -741,6 +763,7 @@ interface as well, by writing <code>ngx.var[1]</code>, <code>ngx.var[2]</code>,
|
|||
ngx.AGAIN (-2)
|
||||
ngx.DONE (-4)
|
||||
</geshi>
|
||||
|
||||
They take the same values of <code>NGX_OK</code>, <code>NGX_AGAIN</code>, <code>NGX_DONE</code>, <code>NGX_ERROR</code>, and etc. But now
|
||||
only [[#ngx.exit|ngx.exit]] only take two of these values, i.e., <code>NGX_OK</code> and <code>NGX_ERROR</code>.
|
||||
|
||||
|
@ -759,6 +782,7 @@ These constants are usually used in [[#ngx.location.capture|ngx.location.catpure
|
|||
|
||||
== HTTP status constants ==
|
||||
'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*''
|
||||
|
||||
<geshi lang="nginx">
|
||||
value = ngx.HTTP_OK (200)
|
||||
value = ngx.HTTP_CREATED (201)
|
||||
|
@ -774,11 +798,13 @@ These constants are usually used in [[#ngx.location.capture|ngx.location.catpure
|
|||
value = ngx.HTTP_NOT_ALLOWED (405)
|
||||
value = ngx.HTTP_GONE (410)
|
||||
value = ngx.HTTP_INTERNAL_SERVER_ERROR (500)
|
||||
value = ngx.HTTP_METHOD_NOT_IMPLEMENTED (501)
|
||||
value = ngx.HTTP_SERVICE_UNAVAILABLE (503)
|
||||
</geshi>
|
||||
|
||||
== Nginx log level constants ==
|
||||
'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*''
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.STDERR
|
||||
ngx.EMERG
|
||||
|
@ -801,9 +827,11 @@ These constants are usually used by the [[#ngx.log|ngx.log]] method.
|
|||
Emit args concatenated to nginx's <code>error.log</code> file, with log level <code>ngx.NOTICE</code> and prefix <code>lua print: </code>.
|
||||
|
||||
It's equivalent to
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.log(ngx.NOTICE, 'lua print: ', a, b, ...)
|
||||
</geshi>
|
||||
|
||||
Lua <code>nil</code> arguments are accepted and result in literal <code>"nil"</code>, and Lua booleans result in <code>"true"</code> or <code>"false"</code>.
|
||||
|
||||
== ngx.ctx ==
|
||||
|
@ -812,6 +840,7 @@ Lua <code>nil</code> arguments are accepted and result in literal <code>"nil"</c
|
|||
This table can be used to store per-request context data for Lua programmers.
|
||||
|
||||
This table has a liftime identical to the current request (just like Nginx variables). Consider the following example,
|
||||
|
||||
<geshi lang="nginx">
|
||||
location /test {
|
||||
rewrite_by_lua '
|
||||
|
@ -826,14 +855,18 @@ This table has a liftime identical to the current request (just like Nginx varia
|
|||
';
|
||||
}
|
||||
</geshi>
|
||||
|
||||
Then <code>GET /test</code> will yield the output
|
||||
|
||||
<geshi lang="bash">
|
||||
foo = nil
|
||||
79
|
||||
</geshi>
|
||||
|
||||
That is, the <code>ngx.ctx.foo</code> entry persists across the rewrite, access, and content phases of a request.
|
||||
|
||||
Also, every request has its own copy, include subrequests, for example:
|
||||
|
||||
<geshi lang="nginx">
|
||||
location /sub {
|
||||
content_by_lua '
|
||||
|
@ -853,16 +886,20 @@ Also, every request has its own copy, include subrequests, for example:
|
|||
';
|
||||
}
|
||||
</geshi>
|
||||
|
||||
Then <code>GET /main</code> will give the output
|
||||
|
||||
<geshi lang="bash">
|
||||
main pre: 73
|
||||
sub pre: nil
|
||||
sub post: 32
|
||||
main post: 73
|
||||
</geshi>
|
||||
|
||||
We can see that modification of the <code>ngx.ctx.blah</code> entry in the subrequest does not affect the one in its parent request. They do have two separate versions of <code>ngx.ctx.blah</code> per se.
|
||||
|
||||
Internal redirection will destroy the original request's <code>ngx.ctx</code> data (if any) and the new request will have an emptied <code>ngx.ctx</code> table. For instance,
|
||||
|
||||
<geshi lang="nginx">
|
||||
location /new {
|
||||
content_by_lua '
|
||||
|
@ -877,15 +914,19 @@ Internal redirection will destroy the original request's <code>ngx.ctx</code> da
|
|||
';
|
||||
}
|
||||
</geshi>
|
||||
|
||||
Then <code>GET /orig</code> will give you
|
||||
|
||||
<geshi lang="bash">
|
||||
nil
|
||||
</geshi>
|
||||
|
||||
rather than the original <code>"hello"</code> value.
|
||||
|
||||
Arbitrary data values can be inserted into this "matic" table, including Lua closures and nested tables. You can also register your own meta methods with it.
|
||||
|
||||
Overriding <code>ngx.ctx</code> with a new Lua table is also supported, for example,
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.ctx = { foo = 32, bar = 54 }
|
||||
</geshi>
|
||||
|
@ -905,9 +946,11 @@ Also note that subrequests just mimic the HTTP interface but there's ''no'' extr
|
|||
Subrequests are completely different from HTTP 301/302 redirection (via [[#ngx.redirect|ngx.redirect]]) and internal redirection (via [[#ngx.exec|ngx.exec]]).
|
||||
|
||||
Here's a basic example:
|
||||
|
||||
<geshi lang="lua">
|
||||
res = ngx.location.capture(uri)
|
||||
</geshi>
|
||||
|
||||
Returns a Lua table with three slots (<code>res.status</code>, <code>res.header</code>, and <code>res.body</code>).
|
||||
|
||||
<code>res.header</code> holds all the response headers of the
|
||||
|
@ -915,18 +958,22 @@ subrequest and it is a normal Lua table. For multi-value response headers,
|
|||
the value is a Lua (array) table that holds all the values in the order that
|
||||
they appear. For instance, if the subrequest response headers contains the following
|
||||
lines:
|
||||
|
||||
<geshi lang="bash">
|
||||
Set-Cookie: a=3
|
||||
Set-Cookie: foo=bar
|
||||
Set-Cookie: baz=blah
|
||||
</geshi>
|
||||
|
||||
Then <code>res.header["Set-Cookie"]</code> will be evaluted to the table value
|
||||
<code>{"a=3", "foo=bar", "baz=blah"}</code>.
|
||||
|
||||
URI query strings can be concatenated to URI itself, for instance,
|
||||
|
||||
<geshi lang="lua">
|
||||
res = ngx.location.capture('/foo/bar?a=3&b=4')
|
||||
</geshi>
|
||||
|
||||
Named locations like <code>@foo</code> are not allowed due to a limitation in
|
||||
the nginx core. Use normal locations combined with the <code>internal</code> directive to
|
||||
prepare internal-only locations.
|
||||
|
@ -936,12 +983,14 @@ argument, which support various options like
|
|||
<code>method</code>, <code>body</code>, <code>args</code>, and <code>share_all_vars</code>.
|
||||
Issuing a POST subrequest, for example,
|
||||
can be done as follows
|
||||
|
||||
<geshi lang="lua">
|
||||
res = ngx.location.capture(
|
||||
'/foo/bar',
|
||||
{ method = ngx.HTTP_POST, body = 'hello, world' }
|
||||
)
|
||||
</geshi>
|
||||
|
||||
See HTTP method constants methods other than POST.
|
||||
The <code>method</code> option is <code>ngx.HTTP_GET</code> by default.
|
||||
|
||||
|
@ -954,25 +1003,31 @@ and lead to confusing issues, use it with special
|
|||
care. So, by default, the option is set to <code>false</code>.
|
||||
|
||||
The <code>args</code> option can specify extra url arguments, for instance,
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.location.capture('/foo?a=1',
|
||||
{ args = { b = 3, c = ':' } }
|
||||
)
|
||||
</geshi>
|
||||
|
||||
is equivalent to
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.location.capture('/foo?a=1&b=3&c=%3a')
|
||||
</geshi>
|
||||
|
||||
that is, this method will automatically escape argument keys and values according to URI rules and
|
||||
concatenating them together into a complete query string. Because it's all done in hand-written C,
|
||||
it should be faster than your own Lua code.
|
||||
|
||||
The <code>args</code> option can also take plain query string:
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.location.capture('/foo?a=1',
|
||||
{ args = 'b=3&c=%3a' } }
|
||||
)
|
||||
</geshi>
|
||||
|
||||
This is functionally identical to the previous examples.
|
||||
|
||||
Note that, by default, subrequests issued by [[#ngx.location.capture|ngx.location.capture]] inherit all the
|
||||
|
@ -990,6 +1045,7 @@ in gzip'd responses that your Lua code is not able to handle properly. So always
|
|||
Just like [[#ngx.location.capture|ngx.location.capture]], but supports multiple subrequests running in parallel.
|
||||
|
||||
This function issue several parallel subrequests specified by the input table, and returns their results in the same order. For example,
|
||||
|
||||
<geshi lang="lua">
|
||||
res1, res2, res3 = ngx.location.capture_multi{
|
||||
{ "/foo", { args = "a=3&b=4" } },
|
||||
|
@ -1005,11 +1061,13 @@ This function issue several parallel subrequests specified by the input table, a
|
|||
...
|
||||
end
|
||||
</geshi>
|
||||
|
||||
This function will not return until all the subrequests terminate.
|
||||
The total latency is the longest latency of the subrequests, instead of their sum.
|
||||
|
||||
When you don't know inadvance how many subrequests you want to issue,
|
||||
you can use Lua tables for both requests and responses. For instance,
|
||||
|
||||
<geshi lang="lua">
|
||||
-- construct the requests table
|
||||
local reqs = {}
|
||||
|
@ -1026,8 +1084,10 @@ you can use Lua tables for both requests and responses. For instance,
|
|||
-- process the response table "resp"
|
||||
end
|
||||
</geshi>
|
||||
|
||||
The [[#ngx.location.capture|ngx.location.capture]] function is just a special form
|
||||
of this function. Logically speaking, the [[#ngx.location.capture|ngx.location.capture]] can be implemented like this
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.location.capture =
|
||||
function (uri, args)
|
||||
|
@ -1040,6 +1100,7 @@ of this function. Logically speaking, the [[#ngx.location.capture|ngx.location.c
|
|||
|
||||
Read and write the current request's response status. This should be called
|
||||
before sending out the response headers.
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.status = ngx.HTTP_CREATED
|
||||
status = ngx.status
|
||||
|
@ -1142,6 +1203,113 @@ Note that <code>ngx.header</code> is not a normal Lua table so you cannot iterat
|
|||
|
||||
For reading ''request'' headers, use the [[#ngx.req.get_headers|ngx.req.get_headers]] function instead.
|
||||
|
||||
== ngx.req.set_uri ==
|
||||
'''syntax:''' ''ngx.req.set_uri(uri, jump?)''
|
||||
|
||||
'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*''
|
||||
|
||||
Rewrite the current request's (parsed) URI by the <code>uri</code> argument. The <code>uri</code> argument must be a Lua string and cannot be of zero length, or a Lua exception will be thrown.
|
||||
|
||||
The optional boolean <code>jump</code> argument can trigger location rematch (or location jump) as [[HttpRewriteModule]]'s [[HttpRewriteModule#rewrite|rewrite]] directive, that is, when <code>jump</code> is <code>true</code> (default to <code>false</code>), this function will never return and it will tell Nginx to try re-searching locations with the new URI value at the later <code>post-rewrite</code> phase and jumping to the new location. Location jump will not be triggered otherwise, and only the current request's URI will be modified, which is also the default behavior. This function will return but with no returned values when the <code>jump</code> argument is <code>false</code> or absent altogether.
|
||||
|
||||
For example, the following nginx config snippet
|
||||
|
||||
<geshi lang="nginx">
|
||||
rewrite ^ /foo last;
|
||||
</geshi>
|
||||
|
||||
can be coded in Lua like this:
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.req.set_uri("/foo", true)
|
||||
</geshi>
|
||||
|
||||
Similarly, Nginx config
|
||||
|
||||
<geshi lang="nginx">
|
||||
rewrite ^ /foo break;
|
||||
</geshi>
|
||||
|
||||
can be coded in Lua as
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.req.set_uri("/foo", false)
|
||||
</geshi>
|
||||
|
||||
or equivalently,
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.req.set_uri("/foo")
|
||||
</geshi>
|
||||
|
||||
The <code>jump</code> can only be set to <code>true</code> in [[#rewrite_by_lua|rewrite_by_lua]] and [[#rewrite_by_lua_file|rewrite_by_lua_file]]. Use of jump in other contexts is prohibited and will throw out a Lua exception.
|
||||
|
||||
A more sophisticated example involving regex substitutions is as follows
|
||||
|
||||
<geshi lang="nginx">
|
||||
location /test {
|
||||
rewrite_by_lua '
|
||||
local uri = ngx.re.sub(ngx.var.uri, "^/test/(.*)", "$1", "o")
|
||||
ngx.req.set_uri(uri)
|
||||
';
|
||||
proxy_pass http://my_backend;
|
||||
}
|
||||
</geshi>
|
||||
|
||||
which is functionally equivalent to
|
||||
|
||||
<geshi lang="nginx">
|
||||
location /test {
|
||||
rewrite ^/test/(.*) /$1 break;
|
||||
proxy_pass http://my_backend;
|
||||
}
|
||||
</geshi>
|
||||
|
||||
Note that you cannot use this interface to rewrite URI arguments, and you need to use [[#ngx.req.set_uri_args|ngx.req.set_uri_args]] for that. For instance, Nginx config
|
||||
|
||||
<geshi lang="nginx">
|
||||
rewrite ^ /foo?a=3? last;
|
||||
</geshi>
|
||||
|
||||
can be coded as
|
||||
|
||||
<geshi lang="nginx">
|
||||
ngx.req.set_uri_args("a=3")
|
||||
ngx.req.set_uri("/foo", true)
|
||||
</geshi>
|
||||
|
||||
or
|
||||
|
||||
<geshi lang="nginx">
|
||||
ngx.req.set_uri_args({a = 3})
|
||||
ngx.req.set_uri("/foo", true)
|
||||
</geshi>
|
||||
|
||||
This interface was first introduced in the <code>v0.3.1rc14</code> release.
|
||||
|
||||
== ngx.req.set_uri_args ==
|
||||
'''syntax:''' ''ngx.req.set_uri_args(args)''
|
||||
|
||||
'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*''
|
||||
|
||||
Rewrite the current request's URI query arguments by the <code>args</code> argument. The <code>args</code> argument can be either a Lua string, as in
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.req.set_uri_args("a=3&b=hello%20world")
|
||||
</geshi>
|
||||
|
||||
or a Lua table holding the query arguments' key-value pairs, as in
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.req.set_uri_args({ a = 3, b = "hello world" })
|
||||
</geshi>
|
||||
|
||||
where in the latter case, this method will automatically escape argument keys and values according to the URI escaping rule.
|
||||
|
||||
This interface was first introduced in the <code>v0.3.1rc13</code> release.
|
||||
|
||||
See also [[#ngx.req.set_uri|ngx.req.set_uri]].
|
||||
|
||||
== ngx.req.get_uri_args ==
|
||||
'''syntax:''' ''args = ngx.req.get_uri_args()''
|
||||
|
||||
|
@ -1150,6 +1318,7 @@ For reading ''request'' headers, use the [[#ngx.req.get_headers|ngx.req.get_head
|
|||
Returns a Lua table holds all of the current request's request URL query arguments.
|
||||
|
||||
Here's an example,
|
||||
|
||||
<geshi lang="nginx">
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
|
@ -1164,38 +1333,51 @@ Here's an example,
|
|||
';
|
||||
}
|
||||
</geshi>
|
||||
|
||||
Then <code>GET /test?foo=bar&bar=baz&bar=blah</code> will yield the response body
|
||||
|
||||
<geshi lang="bash">
|
||||
foo: bar
|
||||
bar: baz, blah
|
||||
</geshi>
|
||||
|
||||
Multiple occurrences of an argument key will result in a table value holding all of the values for that key in order.
|
||||
|
||||
Keys and values will be automatically unescaped according to URI escaping rules. For example, in the above settings, <code>GET /test?a%20b=1%61+2</code> will yield the output
|
||||
|
||||
<geshi lang="bash">
|
||||
a b: 1a 2
|
||||
</geshi>
|
||||
|
||||
Arguments without the <code>=<value></code> parts are treated as boolean arguments. For example, <code>GET /test?foo&bar</code> will yield the outputs
|
||||
|
||||
<geshi lang="bash">
|
||||
foo: true
|
||||
bar: true
|
||||
</geshi>
|
||||
|
||||
That is, they will take Lua boolean values <code>true</code>. However, they're different from arguments taking empty string values. For example, <code>GET /test?foo=&bar=</code> will give something like
|
||||
|
||||
<geshi lang="bash">
|
||||
foo:
|
||||
bar:
|
||||
</geshi>
|
||||
|
||||
Empty key arguments are discarded, for instance, <code>GET /test?=hello&=world</code> will yield empty outputs.
|
||||
|
||||
Updating query arguments via the nginx variable <code>$args</code> (or <code>ngx.var.args</code> in Lua) at runtime are also supported:
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.var.args = "a=3&b=42"
|
||||
local args = ngx.req.get_uri_args()
|
||||
</geshi>
|
||||
|
||||
Here the <code>args</code> table will always look like
|
||||
|
||||
<geshi lang="lua">
|
||||
{a = 3, b = 42}
|
||||
</geshi>
|
||||
|
||||
regardless of the actual request query string.
|
||||
|
||||
== ngx.req.get_post_args ==
|
||||
|
@ -1203,14 +1385,14 @@ regardless of the actual request query string.
|
|||
|
||||
'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*''
|
||||
|
||||
Returns a Lua table holds all of the current request's POST query arguments. It's required to turn on the [[#lua_need_request_body|lua_need_request_body]] directive, or a Lua exception will be thrown.
|
||||
Returns a Lua table holds all of the current request's POST query arguments. It's required to read the request body first by calling [[#ngx.req.read_body|ngx.req.read_body]] or to turn on the [[#lua_need_request_body|lua_need_request_body]] directive, or a Lua exception will be thrown.
|
||||
|
||||
Here's an example,
|
||||
|
||||
<geshi lang="nginx">
|
||||
location = /test {
|
||||
lua_need_request_body on;
|
||||
content_by_lua '
|
||||
local args = ngx.req.get_post_args()
|
||||
ngx.req.read_body()
|
||||
for key, val in pairs(args) do
|
||||
if type(val) == "table" then
|
||||
ngx.say(key, ": ", table.concat(val, ", "))
|
||||
|
@ -1221,37 +1403,50 @@ Here's an example,
|
|||
';
|
||||
}
|
||||
</geshi>
|
||||
|
||||
Then
|
||||
|
||||
<geshi lang="bash">
|
||||
# Post request with the body 'foo=bar&bar=baz&bar=blah'
|
||||
$ curl --data 'foo=bar&bar=baz&bar=blah' localhost/test
|
||||
</geshi>
|
||||
|
||||
will yield the response body like
|
||||
|
||||
<geshi lang="bash">
|
||||
foo: bar
|
||||
bar: baz, blah
|
||||
</geshi>
|
||||
|
||||
Multiple occurrences of an argument key will result in a table value holding all of the values for that key in order.
|
||||
|
||||
Keys and values will be automatically unescaped according to URI escaping rules. For example, in the above settings,
|
||||
|
||||
<geshi lang="bash">
|
||||
# POST request with body 'a%20b=1%61+2'
|
||||
$ curl -d 'a%20b=1%61+2' localhost/test
|
||||
</geshi>
|
||||
|
||||
will yield the output
|
||||
|
||||
<geshi lang="bash">
|
||||
a b: 1a 2
|
||||
</geshi>
|
||||
|
||||
Arguments without the <code>=<value></code> parts are treated as boolean arguments. For example, <code>GET /test?foo&bar</code> will yield the outputs
|
||||
|
||||
<geshi lang="bash">
|
||||
foo: true
|
||||
bar: true
|
||||
</geshi>
|
||||
|
||||
That is, they will take Lua boolean values <code>true</code>. However, they're different from arguments taking empty string values. For example, <code>POST /test</code> with request body <code>foo=&bar=</code> will give something like
|
||||
|
||||
<geshi lang="bash">
|
||||
foo:
|
||||
bar:
|
||||
</geshi>
|
||||
|
||||
Empty key arguments are discarded, for instance, <code>POST /test</code> with body <code>=hello&=world</code> will yield empty outputs.
|
||||
|
||||
== ngx.req.get_headers ==
|
||||
|
@ -1262,26 +1457,34 @@ Empty key arguments are discarded, for instance, <code>POST /test</code> with bo
|
|||
Returns a Lua table holds all of the current request's request headers.
|
||||
|
||||
Here's an example,
|
||||
|
||||
<geshi lang="lua">
|
||||
local h = ngx.req.get_headers()
|
||||
for k, v in pairs(h) do
|
||||
...
|
||||
end
|
||||
</geshi>
|
||||
|
||||
To read an individual header:
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.say("Host: ", ngx.req.get_headers()["Host"])
|
||||
</geshi>
|
||||
|
||||
For multiple instances of request headers like
|
||||
|
||||
<geshi lang="bash">
|
||||
Foo: foo
|
||||
Foo: bar
|
||||
Foo: baz
|
||||
</geshi>
|
||||
|
||||
the value of <code>ngx.req.get_headers()["Foo"]</code> will be a Lua (array) table like this:
|
||||
|
||||
<geshi lang="lua">
|
||||
{"foo", "bar", "baz"}
|
||||
</geshi>
|
||||
|
||||
Another way to read individual request headers is to use <code>ngx.var.http_HEADER</code>, that is, nginx's standard [[HttpCoreModule#$http_HEADER|$http_HEADER]] variables.
|
||||
|
||||
== ngx.req.set_header ==
|
||||
|
@ -1293,30 +1496,164 @@ Set the current request's request header named <code>header_name</code> to value
|
|||
None of the current request's subrequests will be affected.
|
||||
|
||||
Here's an example of setting the <code>Content-Length</code> header:
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.req.set_header("Content-Type", "text/css")
|
||||
</geshi>
|
||||
|
||||
The <code>header_value</code> can take an array list of values,
|
||||
for example,
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.req.set_header("Foo", {"a", "abc"})
|
||||
</geshi>
|
||||
|
||||
will produce two new request headers:
|
||||
|
||||
<geshi lang="bash">
|
||||
Foo: a
|
||||
Foo: abc
|
||||
</geshi>
|
||||
|
||||
and old <code>Foo</code> headers will be overridden if there's any.
|
||||
|
||||
When the <code>header_value</code> argument is <code>nil</code>, the request header will be removed. So
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.req.set_header("X-Foo", nil)
|
||||
</geshi>
|
||||
|
||||
is equivalent to
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.req.clear_header("X-Foo")
|
||||
</geshi>
|
||||
|
||||
== ngx.req.read_body ==
|
||||
'''syntax:''' ''ngx.req.read_body()''
|
||||
|
||||
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*''
|
||||
|
||||
Read the client request body synchronously but still non-blockingly.
|
||||
|
||||
If the request body is already read previously by turning on [[#lua_need_request_body|lua_need_request_body]] or by using other modules, then this function is a no-op and returns immediately.
|
||||
|
||||
If the request body has already been explicitly discarded, either by this module's [[#ngx.req.discard_body|ngx.req.discard_body]] or other modules, this function is a no-op and returns immediately.
|
||||
|
||||
In case of errors, like connection errors while reading the data, this method will throw out a Lua exception ''or'' terminate the current request with the 500 status code immediately.
|
||||
|
||||
You can later either retrieve the request body data via [[#ngx.req.get_body_data|ngx.req.get_body_data]] or retrieve the temporary file name for the body data cached to disk via [[#ngx.req.get_body_file|ngx.req.get_body_file]], depending on
|
||||
|
||||
# whether the current request body is already exceeding your [[HttpCoreModule#client_body_buffer_size|client_body_buffer_size]],
|
||||
# and whether you have turned on [[HttpCoreModule#client_body_in_file_only|client_body_in_file_only]].
|
||||
|
||||
In case that you do not want to read the request body and the current request may have a request body, then it's crucial to use the [[#ngx.req.discard_body|ngx.req.discard_body]] function to explicitly discard the request body, or you'll break HTTP 1.1 keepalive and HTTP 1.1 pipelining.
|
||||
|
||||
Here's a small example:
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.req.read_body()
|
||||
local args = ngx.req.get_post_args()
|
||||
</geshi>
|
||||
|
||||
This function was first introduced in the <code>v0.3.1rc17</code> release.
|
||||
|
||||
== ngx.req.discard_body ==
|
||||
'''syntax:''' ''ngx.req.discard_body()''
|
||||
|
||||
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*''
|
||||
|
||||
Explicitly discard the request body, i.e., read the data on the connection and throw it away immediately. Please note that, simply ignoring request body is not the right way to discard it, you need to call this function, or you'll break things under HTTP 1.1 keepalive or HTTP 1.1 pipelining.
|
||||
|
||||
This function is an asynchronous call and returns immediately.
|
||||
|
||||
If the request body has already been read, this function does nothing and returns immediately.
|
||||
|
||||
This function was first introduced in the <code>v0.3.1rc17</code> release.
|
||||
|
||||
See also [[#ngx.req.read_body|ngx.req.read_body]].
|
||||
|
||||
== ngx.req.get_body_data ==
|
||||
'''syntax:''' ''data = ngx.req.get_body_data()''
|
||||
|
||||
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*''
|
||||
|
||||
Retrieves the in-memory request body data. It returns a Lua string rather than a Lua table holding all the parsed query arguments. If you want the latter, use [[#ngx.req.get_post_args|ngx.req.get_post_args]] instead.
|
||||
|
||||
This function returns <code>nil</code> if
|
||||
# the request body has not been read,
|
||||
# the request body has been read into disk temporary files,
|
||||
# or the request body has zero size.
|
||||
|
||||
If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body automatically, but this is not recommended).
|
||||
|
||||
If the request body has been read into disk files, try calling the [[#ngx.req.get_body_file|ngx.req.get_body_file]] function instead.
|
||||
|
||||
In case that you want to enforce in-memory request bodies, try setting [[HttpCoreModule#client_body_buffer_size|client_body_buffer_size]] to the same size value in [[HttpCoreModule#client_max_body_size|client_max_body_size]].
|
||||
|
||||
Note that calling this function instead of using <code>ngx.var.request_body</code> or <code>ngx.var.echo_request-body</code> is more efficient because it can save one dynamic memory allocation and one data copy.
|
||||
|
||||
This function was first introduced in the <code>v0.3.1rc17</code> release.
|
||||
|
||||
See also [[#ngx.req.get_body_file|ngx.req.get_body_file]].
|
||||
|
||||
== ngx.req.get_body_file ==
|
||||
'''syntax:''' ''file_name = ngx.req.get_body_file()''
|
||||
|
||||
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*''
|
||||
|
||||
Retrieves the file name for the in-file request body data. Returns <code>nil</code> if the request body has not been read or has been read into memory.
|
||||
|
||||
The returned file is read only and is usually cleaned up automatically by Nginx's memory pool. It should not be modified, renamed, or removed by your own Lua code.
|
||||
|
||||
If the request body has not been read yet, call [[#ngx.req.read_body|ngx.req.read_body]] first (or turned on [[#lua_need_request_body|lua_need_request_body]] to force this module to read the request body automatically, but this is not recommended).
|
||||
|
||||
If the request body has been read into memory, try calling the [[#ngx.req.get_body_data|ngx.req.get_body_data]] function instead.
|
||||
|
||||
In case that you want to enforce in-file request bodies, try turning on [[HttpCoreModule#client_body_in_file_only|client_body_in_file_only]].
|
||||
|
||||
This function was first introduced in the <code>v0.3.1rc17</code> release.
|
||||
|
||||
See also [[#ngx.req.get_body_data|ngx.req.get_body_data]].
|
||||
|
||||
== ngx.req.set_body_data ==
|
||||
'''syntax:''' ''ngx.req.set_body_data(data)''
|
||||
|
||||
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*''
|
||||
|
||||
Set the current request's request body using the in-memory data specified by the <code>data</code> argument.
|
||||
|
||||
If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively.
|
||||
|
||||
This function requires patching the Nginx core to function properly because the Nginx core does not allow modifying request bodies by the current design. Here is a patch for Nginx 1.0.8: [https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.0.8-allow_request_body_updating.patch nginx-1.0.8-allow_request_body_updating.patch], and this patch should be applied cleanly to other releases of Nginx as well.
|
||||
|
||||
If you're using [http://openresty.org/ ngx_openresty] 1.0.8.17+, then you've already had this patch applied.
|
||||
|
||||
This function was first introduced in the <code>v0.3.1rc18</code> release.
|
||||
|
||||
See also [[#ngx.req.set_body_file|ngx.req.set_body_file]].
|
||||
|
||||
== ngx.req.set_body_file ==
|
||||
'''syntax:''' ''ngx.req.set_body_file(file_name, auto_clean?)''
|
||||
|
||||
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*''
|
||||
|
||||
Set the current request's request body using the in-file data specified by the <code>file_name</code> argument.
|
||||
|
||||
If the optional <code>auto_clean</code> argument is given a <code>true</code> value, then this file will be automatically removed at request completion or the next time this function or [[#ngx.req.set_body_data|ngx.req.set_body_data]] are called in the same request. The <code>auto_clean</code> is default to <code>false</code>.
|
||||
|
||||
You must ensure that the file specified by the <code>file_name</code> argument exists and is readable by an Nginx worker process by setting its permission properly. Otherwise a Lua exception will be thrown.
|
||||
|
||||
If the current request's request body has not been read, then it will be properly discarded. When the current request's request body has been read into memory or buffered into a disk file, then the old request body's memory will be freed or the disk file will be cleaned up immediately, respectively.
|
||||
|
||||
This function requires patching the Nginx core to function properly because the Nginx core does not allow modifying request bodies by the current design. Here is a patch for Nginx 1.0.8: [https://github.com/agentzh/ngx_openresty/blob/master/patches/nginx-1.0.8-allow_request_body_updating.patch nginx-1.0.8-allow_request_body_updating.patch], and this patch should be applied cleanly to other releases of Nginx as well.
|
||||
|
||||
If you're using [http://openresty.org/ ngx_openresty] 1.0.8.17+, then you've already had this patch applied.
|
||||
|
||||
This function was first introduced in the <code>v0.3.1rc18</code> release.
|
||||
|
||||
See also [[#ngx.req.set_body_data|ngx.req.set_body_data]].
|
||||
|
||||
== ngx.req.clear_header ==
|
||||
'''syntax:''' ''ngx.req.clear_header(header_name)''
|
||||
|
||||
|
@ -1407,7 +1744,7 @@ This method is very much like the [[HttpRewriteModule#rewrite|rewrite]] directiv
|
|||
[[HttpRewriteModule]], for example, this <code>nginx.conf</code> snippet
|
||||
|
||||
<geshi lang="nginx">
|
||||
rewrite ^ /foo redirect; # nginx config
|
||||
rewrite ^ /foo? redirect; # nginx config
|
||||
</geshi>
|
||||
|
||||
is equivalent to the following Lua code
|
||||
|
@ -1419,7 +1756,7 @@ is equivalent to the following Lua code
|
|||
while
|
||||
|
||||
<geshi lang="nginx">
|
||||
rewrite ^ /foo permanent; # nginx config
|
||||
rewrite ^ /foo? permanent; # nginx config
|
||||
</geshi>
|
||||
|
||||
is equivalent to
|
||||
|
@ -1428,6 +1765,12 @@ is equivalent to
|
|||
return ngx.redirect('/foo', ngx.HTTP_MOVED_PERMANENTLY) -- Lua code
|
||||
</geshi>
|
||||
|
||||
URI arguments can be specified as well, for example:
|
||||
|
||||
<geshi lang="lua">
|
||||
return ngx.redirect('/foo?a=3&b=4')
|
||||
</geshi>
|
||||
|
||||
== ngx.send_headers ==
|
||||
'''syntax:''' ''ngx.send_headers()''
|
||||
|
||||
|
@ -1537,6 +1880,12 @@ The effect in action:
|
|||
This is our own content
|
||||
</geshi>
|
||||
|
||||
Number literals can be used directly as the argument, for instance,
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.exit(501)
|
||||
</geshi>
|
||||
|
||||
== ngx.eof ==
|
||||
'''syntax:''' ''ngx.eof()''
|
||||
|
||||
|
@ -1638,32 +1987,38 @@ This is the UTC time.
|
|||
'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*''
|
||||
|
||||
Returns a formated string can be used as the cookie expiration time. The parameter <code>sec</code> is the timestamp in seconds (like those returned from [[#ngx.time|ngx.time]]).
|
||||
|
||||
<geshi lang="nginx">
|
||||
ngx.say(ngx.cookie_time(1290079655))
|
||||
-- yields "Thu, 18-Nov-10 11:27:35 GMT"
|
||||
</geshi>
|
||||
|
||||
== ngx.http_time ==
|
||||
'''syntax:''' ''str = ngx.http_time(sec)''
|
||||
|
||||
'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*''
|
||||
|
||||
Returns a formated string can be used as the http header time (for example, being used in <code>Last-Modified</code> header). The parameter <code>sec</code> is the timestamp in seconds (like those returned from [[#ngx.time|ngx.time]]).
|
||||
|
||||
<geshi lang="nginx">
|
||||
ngx.say(ngx.http_time(1290079655))
|
||||
-- yields "Thu, 18 Nov 10 11:27:35 GMT"
|
||||
</geshi>
|
||||
|
||||
== ngx.parse_http_time ==
|
||||
'''syntax:''' ''sec = ngx.parse_http_time(str)''
|
||||
|
||||
'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*''
|
||||
|
||||
Parse the http time string (as returned by [[#ngx.http_time|ngx.http_time]]) into seconds. Returns the seconds or <code>nil</code> if the input string is in bad forms.
|
||||
|
||||
<geshi lang="nginx">
|
||||
local time = ngx.parse_http_time("Thu, 18 Nov 10 11:27:35 GMT")
|
||||
if time == nil then
|
||||
...
|
||||
end
|
||||
</geshi>
|
||||
|
||||
== ngx.is_subrequest ==
|
||||
'''syntax:''' ''value = ngx.is_subrequest''
|
||||
|
||||
|
@ -2015,13 +2370,14 @@ The installation steps are usually as simple as <code>./configure && make && mak
|
|||
Alternatively, you can compile this module with nginx core's source by hand:
|
||||
|
||||
# Install Lua or LuaJIT into your system. At least Lua 5.1 is required. Lua can be obtained freely from its project [http://www.lua.org/ homepage]. For Ubuntu/Debian users, just install the liblua5.1-0-dev package (or something like that).
|
||||
# Download the latest version of the release tarball of the ngx_devel_kit (NDK) module from lua-nginx-module [http://github.com/simpl/ngx_devel_kit/downloads file list].
|
||||
# Download the latest version of the release tarball of this module from lua-nginx-module [http://github.com/chaoslawful/lua-nginx-module/downloads file list].
|
||||
# Download the latest version of the release tarball of the ngx_devel_kit (NDK) module from lua-nginx-module [http://github.com/simpl/ngx_devel_kit/tags file list].
|
||||
# Download the latest version of the release tarball of this module from lua-nginx-module [http://github.com/chaoslawful/lua-nginx-module/tags file list].
|
||||
# Grab the nginx source code from [http://nginx.org/ nginx.org], for example, the version 1.0.5 (see nginx compatibility), and then build the source with this module:
|
||||
|
||||
<geshi lang="bash">
|
||||
$ wget 'http://nginx.org/download/nginx-1.0.5.tar.gz'
|
||||
$ tar -xzvf nginx-1.0.5.tar.gz
|
||||
$ cd nginx-1.0.5/
|
||||
wget 'http://nginx.org/download/nginx-1.0.5.tar.gz'
|
||||
tar -xzvf nginx-1.0.5.tar.gz
|
||||
cd nginx-1.0.5/
|
||||
|
||||
# tell nginx's build system where to find lua:
|
||||
export LUA_LIB=/path/to/lua/lib
|
||||
|
@ -2032,12 +2388,12 @@ Alternatively, you can compile this module with nginx core's source by hand:
|
|||
# export LUAJIT_INC=/path/to/luajit/include/luajit-2.0
|
||||
|
||||
# Here we assume you would install you nginx under /opt/nginx/.
|
||||
$ ./configure --prefix=/opt/nginx \
|
||||
./configure --prefix=/opt/nginx \
|
||||
--add-module=/path/to/ngx_devel_kit \
|
||||
--add-module=/path/to/lua-nginx-module
|
||||
|
||||
$ make -j2
|
||||
$ make install
|
||||
make -j2
|
||||
make install
|
||||
</geshi>
|
||||
|
||||
= Compatibility =
|
||||
|
@ -2110,22 +2466,26 @@ filtering chain affects a lot. The correct configure adding order is:
|
|||
# rds-json-nginx-module
|
||||
|
||||
= TODO =
|
||||
|
||||
* Add <code>ignore_resp_headers</code>, <code>ignore_resp_body</code>, and <code>ignore_resp</code> options to [[#ngx.location.capture|ngx.location.capture]] and ngx.location.capture_multi` methods, to allow micro performance tuning on the user side.
|
||||
* Add directives to run lua codes when nginx stops/reloads.
|
||||
* Deal with TCP 3-second delay problem under great connection harness.
|
||||
* add <code>ignore_resp_headers</code>, <code>ignore_resp_body</code>, and <code>ignore_resp</code> options to [[#ngx.location.capture|ngx.location.capture]] and ngx.location.capture_multi` methods, to allow micro performance tuning on the user side.
|
||||
* add directives to run lua codes when nginx stops/reloads.
|
||||
* deal with TCP 3-second delay problem under great connection harness.
|
||||
* add options to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] in order to share and copy a particular set of nginx variables with subrequests, specified by the user.
|
||||
* add an option to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] so as to specify the [[#ngx.ctx|ngx.ctx]] table for subrequests.
|
||||
* expose nginx's shared memory facility to the Lua land.
|
||||
* add support for multi-value arguments to [[#ngx.req.set_uri_args]] if its <code>args</code> argument is a Lua table.
|
||||
|
||||
= Future Plan =
|
||||
|
||||
* Add the <code>lua_require</code> directive to load module into main thread's globals.
|
||||
* Add the "cosocket" mechamism that will emulate a common set of Lua socket API that will give you totally transparently non-blocking capability out of the box by means of a completely new upstream layer atop the nginx event model and no nginx subrequest overheads.
|
||||
* Add Lua code automatic time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks.
|
||||
* Make set_by_lua using the same mechanism as content_by_lua.
|
||||
* add the <code>lua_require</code> directive to load module into main thread's globals.
|
||||
* add the "cosocket" mechamism that will emulate a common set of Lua socket API that will give you totally transparently non-blocking capability out of the box by means of a completely new upstream layer atop the nginx event model and no nginx subrequest overheads.
|
||||
* add Lua code automatic time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks.
|
||||
* make set_by_lua using the same mechanism as content_by_lua.
|
||||
* add coroutine API back to the Lua land.
|
||||
|
||||
= Known Issues =
|
||||
|
||||
* As ngx_lua's predefined Nginx I/O APIs use coroutine yielding/resuming mechanism, the user code should not call any Lua modules that use coroutine API to prevent obfuscating the predefined Nginx APIs like [[#ngx.location.capture|ngx.location.capture]] (actually coroutine modules have been masked off in [[#content_by_lua|content_by_lua]] directives and others). This limitation is a little crucial, but don't worry, we're working on an alternative coroutine implementation that can fit into the Nginx event model. When it is done, the user code will be able to use the Lua coroutine mechanism freely as in standard Lua again!
|
||||
* Because the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi], [[#ngx.redirect|ngx.redirect]], [[#ngx.exec|ngx.exec]], and [[#ngx.exit|ngx.exit]] cannot be used within the context of a Lua [http://www.lua.org/manual/5.1/manual.html#pdf-pcall pcall()] or [http://www.lua.org/manual/5.1/manual.html#pdf-xpcall xpcall()] when the standard Lua 5.1 interpreter is used; you'll get the error <code>attempt to yield across metamethod/C-call boundary</code>. To fix this, please use LuaJIT 2.0 instead, because LuaJIT 2.0 supports a fully resume-able VM.
|
||||
* Because the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [[#ngx.location.capture|ngx.location.capture]], [[#ngx.location.capture_multi|ngx.location.capture_multi]], [[#ngx.redirect|ngx.redirect]], [[#ngx.exec|ngx.exec]], and [[#ngx.exit|ngx.exit]] cannot be used within the context of a Lua [http://www.lua.org/manual/5.1/manual.html#pdf-pcall pcall()] or [http://www.lua.org/manual/5.1/manual.html#pdf-xpcall xpcall()] when the standard Lua 5.1 interpreter is used; you'll get the error <code>attempt to yield across metamethod/C-call boundary</code>. To fix this, please use LuaJIT 2.0 instead, because LuaJIT 2.0 supports a fully resume-able VM.
|
||||
* The [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] Lua methods cannot capture locations configured by [[HttpEchoModule]]'s [[HttpEchoModule#echo_location|echo_location]], [[HttpEchoModule#echo_location_async|echo_location_async]], [[HttpEchoModule#echo_subrequest|echo_subrequest]], or [[HttpEchoModule#echo_subrequest_async|echo_subrequest_async]] directives. This won't be fixed in the future due to technical problems.
|
||||
* '''WATCH OUT: Globals WON'T persist between requests''', because of the one-coroutine-per-request isolation design. Especially watch yourself when using <code>require()</code> to import modules, and use this form:
|
||||
<geshi lang="nginx">
|
||||
|
|
|
@ -9,142 +9,8 @@
|
|||
#include "ngx_http_lua_cache.h"
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
int cc_ref;
|
||||
lua_State *cc;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_cleanup_t *cln;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
cc = ngx_http_lua_new_thread(r, L, &cc_ref);
|
||||
|
||||
if (cc == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"lua: failed to create new coroutine "
|
||||
"to handle request");
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* move code closure to new coroutine */
|
||||
lua_xmove(L, cc, 1);
|
||||
|
||||
/* set closure's env table to new coroutine's globals table */
|
||||
lua_pushvalue(cc, LUA_GLOBALSINDEX);
|
||||
lua_setfenv(cc, -2);
|
||||
|
||||
/* save reference of code to ease forcing stopping */
|
||||
lua_pushvalue(cc, -1);
|
||||
lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE);
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
lua_pushlightuserdata(cc, r);
|
||||
lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ initialize request context */
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_reset_ctx(r, L, ctx);
|
||||
|
||||
ctx->entered_access_phase = 1;
|
||||
|
||||
ctx->cc = cc;
|
||||
ctx->cc_ref = cc_ref;
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ register request cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_http_cleanup_add(r, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup;
|
||||
cln->data = r;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
return ngx_http_lua_run_thread(L, r, ctx, 0);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_access_handler_file(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
char *err;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
/* Eval nginx variables in code path string first */
|
||||
if (ngx_http_complex_value(r, &llcf->access_src, &eval_src) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
L = lmcf->lua;
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->access_src_key,
|
||||
&err, llcf->enable_code_cache ? 1 : 0);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
if (err == NULL) {
|
||||
err = "unknown error";
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"Failed to load Lua inlined code: %s", err);
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
assert(lua_isfunction(L, -1));
|
||||
|
||||
rc = ngx_http_lua_access_by_chunk(L, r);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
return NGX_HTTP_OK;
|
||||
}
|
||||
|
||||
if (rc >= NGX_HTTP_OK && rc < NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
static ngx_int_t ngx_http_lua_access_by_chunk(lua_State *L,
|
||||
ngx_http_request_t *r);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
|
@ -241,10 +107,11 @@ ngx_http_lua_access_handler(ngx_http_request_t *r)
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (llcf->force_read_body &&
|
||||
! ctx->read_body_done &&
|
||||
((r->method & NGX_HTTP_POST) || (r->method & NGX_HTTP_PUT)))
|
||||
{
|
||||
if (llcf->force_read_body && !ctx->read_body_done) {
|
||||
r->request_body_in_single_buf = 1;
|
||||
r->request_body_in_persistent_file = 1;
|
||||
r->request_body_in_clean_file = 1;
|
||||
|
||||
rc = ngx_http_read_client_request_body(r,
|
||||
ngx_http_lua_generic_phase_post_read);
|
||||
|
||||
|
@ -295,9 +162,128 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r)
|
|||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
rc = ngx_http_lua_access_by_chunk(L, r);
|
||||
return ngx_http_lua_access_by_chunk(L, r);
|
||||
}
|
||||
|
||||
dd("access by chunk returns %d", (int) rc);
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_access_handler_file(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
char *err;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
/* Eval nginx variables in code path string first */
|
||||
if (ngx_http_complex_value(r, &llcf->access_src, &eval_src) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
L = lmcf->lua;
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->access_src_key,
|
||||
&err, llcf->enable_code_cache ? 1 : 0);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
if (err == NULL) {
|
||||
err = "unknown error";
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"Failed to load Lua inlined code: %s", err);
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_http_lua_access_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
int cc_ref;
|
||||
lua_State *cc;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_cleanup_t *cln;
|
||||
ngx_int_t rc;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
cc = ngx_http_lua_new_thread(r, L, &cc_ref);
|
||||
|
||||
if (cc == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"lua: failed to create new coroutine "
|
||||
"to handle request");
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* move code closure to new coroutine */
|
||||
lua_xmove(L, cc, 1);
|
||||
|
||||
/* set closure's env table to new coroutine's globals table */
|
||||
lua_pushvalue(cc, LUA_GLOBALSINDEX);
|
||||
lua_setfenv(cc, -2);
|
||||
|
||||
/* save reference of code to ease forcing stopping */
|
||||
lua_pushvalue(cc, -1);
|
||||
lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE);
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
lua_pushlightuserdata(cc, r);
|
||||
lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ initialize request context */
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_reset_ctx(r, L, ctx);
|
||||
|
||||
ctx->entered_access_phase = 1;
|
||||
|
||||
ctx->cc = cc;
|
||||
ctx->cc_ref = cc_ref;
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ register request cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_http_cleanup_add(r, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup;
|
||||
cln->data = r;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
rc = ngx_http_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
|
@ -308,7 +294,8 @@ ngx_http_lua_access_handler_inline(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
return NGX_HTTP_OK;
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
if (rc >= NGX_HTTP_OK && rc < NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
/* vim:set ft=c ts=4 sw=4 et fdm=marker: */
|
||||
|
||||
#ifndef NGX_HTTP_LUA_ACCESS_BY_H__
|
||||
#define NGX_HTTP_LUA_ACCESS_BY_H__
|
||||
#ifndef NGX_HTTP_LUA_ACCESSBY_H
|
||||
#define NGX_HTTP_LUA_ACCESSBY_H
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_access_handler(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_access_handler_inline(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_access_handler_file(ngx_http_request_t *r);
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* NGX_HTTP_LUA_ACCESSBY_H */
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
|
||||
#include "ddebug.h"
|
||||
|
||||
#include "ngx_http_lua_args.h"
|
||||
|
@ -10,11 +9,68 @@
|
|||
|
||||
static int ngx_http_lua_parse_args(ngx_http_request_t *r, lua_State *L,
|
||||
u_char *buf, u_char *last);
|
||||
static int ngx_http_lua_ngx_req_set_uri_args(lua_State *L);
|
||||
static int ngx_http_lua_ngx_req_get_uri_args(lua_State *L);
|
||||
static int ngx_http_lua_ngx_req_get_post_args(lua_State *L);
|
||||
|
||||
|
||||
int
|
||||
static int
|
||||
ngx_http_lua_ngx_req_set_uri_args(lua_State *L) {
|
||||
ngx_http_request_t *r;
|
||||
ngx_str_t args;
|
||||
const char *msg;
|
||||
size_t len;
|
||||
u_char *p;
|
||||
|
||||
if (lua_gettop(L) != 1) {
|
||||
return luaL_error(L, "expecting 1 argument but seen %d",
|
||||
lua_gettop(L));
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
switch (lua_type(L, 1)) {
|
||||
case LUA_TNUMBER:
|
||||
case LUA_TSTRING:
|
||||
p = (u_char *) lua_tolstring(L, 1, &len);
|
||||
|
||||
args.data = ngx_palloc(r->pool, len);
|
||||
ngx_memcpy(args.data, p, len);
|
||||
|
||||
args.len = len;
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
ngx_http_lua_process_args_option(r, L, 1, &args);
|
||||
|
||||
dd("args: %.*s", (int) args.len, args.data);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
msg = lua_pushfstring(L, "string, number, or table expected, "
|
||||
"but got %s", luaL_typename(L, 2));
|
||||
return luaL_argerror(L, 1, msg);
|
||||
}
|
||||
|
||||
dd("args: %.*s", (int) args.len, args.data);
|
||||
|
||||
r->args.data = args.data;
|
||||
r->args.len = args.len;
|
||||
|
||||
r->valid_unparsed_uri = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_get_uri_args(lua_State *L) {
|
||||
ngx_http_request_t *r;
|
||||
u_char *buf;
|
||||
|
@ -56,7 +112,7 @@ ngx_http_lua_ngx_req_get_uri_args(lua_State *L) {
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
static int
|
||||
ngx_http_lua_ngx_req_get_post_args(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
|
@ -253,6 +309,9 @@ ngx_http_lua_parse_args(ngx_http_request_t *r, lua_State *L, u_char *buf,
|
|||
void
|
||||
ngx_http_lua_inject_req_args_api(lua_State *L)
|
||||
{
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_set_uri_args);
|
||||
lua_setfield(L, -2, "set_uri_args");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_get_uri_args);
|
||||
lua_setfield(L, -2, "get_uri_args");
|
||||
|
||||
|
|
|
@ -39,9 +39,6 @@ ngx_http_lua_capture_header_filter(ngx_http_request_t *r)
|
|||
ngx_http_lua_ctx_t *old_ctx;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua capture header filter, uri \"%V\"", &r->uri);
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("old ctx: %p", ctx);
|
||||
|
@ -74,7 +71,7 @@ ngx_http_lua_capture_header_filter(ngx_http_request_t *r)
|
|||
|
||||
if (ctx && ctx->capture) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua capturing request body");
|
||||
"lua capturing response body");
|
||||
|
||||
/* force subrequest response body buffer in memory */
|
||||
r->filter_need_in_memory = 1;
|
||||
|
@ -93,9 +90,6 @@ ngx_http_lua_capture_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
|||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_ctx_t *pr_ctx;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua capture body filter, uri \"%V\"", &r->uri);
|
||||
|
||||
if (in == NULL) {
|
||||
return ngx_http_lua_next_body_filter(r, NULL);
|
||||
}
|
||||
|
@ -108,9 +102,6 @@ ngx_http_lua_capture_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
|||
return ngx_http_lua_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua body filter");
|
||||
|
||||
if (ctx->run_post_subrequest) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua body filter skipped because post subrequest already run");
|
||||
|
@ -129,8 +120,9 @@ ngx_http_lua_capture_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
|||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua body filter capturing output");
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua capture body filter capturing response body, uri \"%V\"",
|
||||
&r->uri);
|
||||
|
||||
rc = ngx_http_lua_add_copy_chain(r, pr_ctx, &ctx->body, in);
|
||||
|
||||
|
|
|
@ -80,6 +80,8 @@ typedef struct {
|
|||
|
||||
|
||||
typedef struct {
|
||||
ngx_buf_tag_t tag;
|
||||
|
||||
ngx_flag_t force_read_body; /* whether force request body to
|
||||
be read */
|
||||
|
||||
|
@ -116,8 +118,6 @@ typedef struct {
|
|||
u_char *header_filter_src_key;
|
||||
/* cached key for header_filter_src */
|
||||
|
||||
|
||||
|
||||
} ngx_http_lua_loc_conf_t;
|
||||
|
||||
|
||||
|
@ -178,6 +178,7 @@ typedef struct {
|
|||
|
||||
unsigned waiting_more_body:1; /* 1: waiting for more data;
|
||||
0: no need to wait */
|
||||
unsigned req_read_body_done:1; /* used by ngx.req.read_body */
|
||||
|
||||
unsigned headers_set:1;
|
||||
unsigned entered_rewrite_phase:1;
|
||||
|
@ -187,7 +188,6 @@ typedef struct {
|
|||
/* whether it has run post_subrequest */
|
||||
unsigned run_post_subrequest:1;
|
||||
unsigned req_header_cached:1;
|
||||
|
||||
} ngx_http_lua_ctx_t;
|
||||
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf)
|
|||
|
||||
conf->force_read_body = NGX_CONF_UNSET;
|
||||
conf->enable_code_cache = NGX_CONF_UNSET;
|
||||
conf->tag = (ngx_buf_tag_t) &ngx_http_lua_module;
|
||||
|
||||
return conf;
|
||||
}
|
||||
|
|
|
@ -90,6 +90,9 @@ ngx_http_lua_inject_http_consts(lua_State *L)
|
|||
lua_pushinteger(L, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
lua_setfield(L, -2, "HTTP_INTERNAL_SERVER_ERROR");
|
||||
|
||||
lua_pushinteger(L, 501);
|
||||
lua_setfield(L, -2, "HTTP_METHOD_NOT_IMPLEMENTED");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_SERVICE_UNAVAILABLE);
|
||||
lua_setfield(L, -2, "HTTP_SERVICE_UNAVAILABLE");
|
||||
/* }}} */
|
||||
|
|
|
@ -143,10 +143,11 @@ ngx_http_lua_content_handler(ngx_http_request_t *r)
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (llcf->force_read_body &&
|
||||
! ctx->read_body_done &&
|
||||
((r->method & NGX_HTTP_POST) || (r->method & NGX_HTTP_PUT)))
|
||||
{
|
||||
if (llcf->force_read_body && !ctx->read_body_done) {
|
||||
r->request_body_in_single_buf = 1;
|
||||
r->request_body_in_persistent_file = 1;
|
||||
r->request_body_in_clean_file = 1;
|
||||
|
||||
rc = ngx_http_read_client_request_body(r,
|
||||
ngx_http_lua_content_phase_post_read);
|
||||
|
||||
|
@ -176,8 +177,6 @@ ngx_http_lua_content_phase_post_read(ngx_http_request_t *r)
|
|||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
r->read_event_handler = ngx_http_request_empty_handler;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
ctx->read_body_done = 1;
|
||||
|
|
|
@ -71,7 +71,7 @@ ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r)
|
|||
#if (NGX_PCRE)
|
||||
ngx_http_lua_inject_regex_api(L);
|
||||
#endif
|
||||
ngx_http_lua_inject_req_api(L);
|
||||
ngx_http_lua_inject_req_api_no_io(L);
|
||||
ngx_http_lua_inject_resp_header_api(L);
|
||||
ngx_http_lua_inject_variable_api(L);
|
||||
ngx_http_lua_inject_misc_api(L);
|
||||
|
@ -244,9 +244,6 @@ ngx_http_lua_header_filter(ngx_http_request_t *r)
|
|||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_int_t rc;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua header filter, uri \"%V\"", &r->uri);
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->header_filter_handler == NULL) {
|
||||
|
@ -254,6 +251,9 @@ ngx_http_lua_header_filter(ngx_http_request_t *r)
|
|||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua header filter for header_filter_by_lua , uri \"%V\"", &r->uri);
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
|
|
@ -0,0 +1,675 @@
|
|||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
#include "ngx_http_lua_req_body.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_headers_in.h"
|
||||
|
||||
|
||||
static int ngx_http_lua_ngx_req_read_body(lua_State *L);
|
||||
static void ngx_http_lua_req_body_post_read(ngx_http_request_t *r);
|
||||
static int ngx_http_lua_ngx_req_discard_body(lua_State *L);
|
||||
static int ngx_http_lua_ngx_req_get_body_data(lua_State *L);
|
||||
static int ngx_http_lua_ngx_req_get_body_file(lua_State *L);
|
||||
static int ngx_http_lua_ngx_req_set_body_data(lua_State *L);
|
||||
static void ngx_http_lua_pool_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
|
||||
static int ngx_http_lua_ngx_req_set_body_file(lua_State *L);
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_req_body_api(lua_State *L)
|
||||
{
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_read_body);
|
||||
lua_setfield(L, -2, "read_body");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_discard_body);
|
||||
lua_setfield(L, -2, "discard_body");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_get_body_data);
|
||||
lua_setfield(L, -2, "get_body_data");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_get_body_file);
|
||||
lua_setfield(L, -2, "get_body_file");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_set_body_data);
|
||||
lua_setfield(L, -2, "set_body_data");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_set_body_file);
|
||||
lua_setfield(L, -2, "set_body_file");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_read_body(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
int n;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_int_t rc;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n != 0) {
|
||||
return luaL_error(L, "expecting 0 arguments but seen %d", n);
|
||||
}
|
||||
|
||||
lua_getglobal(L, GLOBALS_SYMBOL_REQUEST);
|
||||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
r->request_body_in_single_buf = 1;
|
||||
r->request_body_in_persistent_file = 1;
|
||||
r->request_body_in_clean_file = 1;
|
||||
|
||||
#if 1
|
||||
if (r->request_body_in_file_only) {
|
||||
r->request_body_file_log_level = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "request context is null");
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua start to read buffered request body");
|
||||
|
||||
rc = ngx_http_read_client_request_body(r, ngx_http_lua_req_body_post_read);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return luaL_error(L, "failed to read request body");
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua read buffered request body requires I/O interruptions");
|
||||
|
||||
ctx->waiting_more_body = 1;
|
||||
ctx->req_read_body_done = 0;
|
||||
|
||||
return lua_yield(L, 0);
|
||||
}
|
||||
|
||||
/* rc == NGX_OK */
|
||||
|
||||
ctx->req_read_body_done = 0;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua has read buffered request body in a single run");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_req_body_post_read(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua req body post read");
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
ctx->req_read_body_done = 1;
|
||||
|
||||
#if defined(nginx_version) && nginx_version >= 8011
|
||||
r->main->count--;
|
||||
#endif
|
||||
|
||||
if (ctx->waiting_more_body) {
|
||||
ctx->waiting_more_body = 0;
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_lua_wev_handler(r);
|
||||
|
||||
} else {
|
||||
ngx_http_core_run_phases(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_discard_body(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_int_t rc;
|
||||
int n;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n != 0) {
|
||||
return luaL_error(L, "expecting 0 arguments but seen %d", n);
|
||||
}
|
||||
|
||||
lua_getglobal(L, GLOBALS_SYMBOL_REQUEST);
|
||||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
rc = ngx_http_discard_request_body(r);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return luaL_error(L, "failed to discard request body");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_get_body_data(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
int n;
|
||||
size_t len;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n != 0) {
|
||||
return luaL_error(L, "expecting 0 arguments but seen %d", n);
|
||||
}
|
||||
|
||||
lua_getglobal(L, GLOBALS_SYMBOL_REQUEST);
|
||||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (r->request_body == NULL
|
||||
|| r->request_body->temp_file
|
||||
|| r->request_body->bufs == NULL)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
len = r->request_body->bufs->buf->last - r->request_body->bufs->buf->pos;
|
||||
|
||||
if (len == 0) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_pushlstring(L, (char *) r->request_body->bufs->buf->pos, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_get_body_file(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
int n;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n != 0) {
|
||||
return luaL_error(L, "expecting 0 arguments but seen %d", n);
|
||||
}
|
||||
|
||||
lua_getglobal(L, GLOBALS_SYMBOL_REQUEST);
|
||||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (r->request_body == NULL || r->request_body->temp_file == NULL) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dd("XXX file directio: %u, f:%u, m:%u, t:%u, end - pos %d, size %d",
|
||||
r->request_body->temp_file->file.directio,
|
||||
r->request_body->bufs->buf->in_file,
|
||||
r->request_body->bufs->buf->memory,
|
||||
r->request_body->bufs->buf->temporary,
|
||||
(int) (r->request_body->bufs->buf->end -
|
||||
r->request_body->bufs->buf->pos),
|
||||
(int) ngx_buf_size(r->request_body->bufs->buf)
|
||||
);
|
||||
|
||||
lua_pushlstring(L, (char *) r->request_body->temp_file->file.name.data,
|
||||
r->request_body->temp_file->file.name.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_set_body_data(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
int n;
|
||||
ngx_http_request_body_t *rb;
|
||||
ngx_temp_file_t *tf;
|
||||
ngx_buf_t *b;
|
||||
ngx_str_t body, key, value;
|
||||
#if 1
|
||||
ngx_int_t rc;
|
||||
#endif
|
||||
ngx_chain_t *cl;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n != 1) {
|
||||
return luaL_error(L, "expecting 1 arguments but seen %d", n);
|
||||
}
|
||||
|
||||
body.data = (u_char *) luaL_checklstring(L, 1, &body.len);
|
||||
|
||||
lua_getglobal(L, GLOBALS_SYMBOL_REQUEST);
|
||||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (r->request_body == NULL) {
|
||||
|
||||
#if 1
|
||||
rc = ngx_http_discard_request_body(r);
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return luaL_error(L, "failed to discard request body");
|
||||
}
|
||||
#endif
|
||||
|
||||
rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
|
||||
if (rb == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
|
||||
r->request_body = rb;
|
||||
|
||||
} else {
|
||||
rb = r->request_body;
|
||||
}
|
||||
|
||||
tf = rb->temp_file;
|
||||
|
||||
if (tf) {
|
||||
if (tf->file.fd != NGX_INVALID_FILE) {
|
||||
|
||||
dd("cleaning temp file %.*s", (int) tf->file.name.len,
|
||||
tf->file.name.data);
|
||||
|
||||
ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd);
|
||||
tf->file.fd = NGX_INVALID_FILE;
|
||||
|
||||
dd("temp file cleaned: %.*s", (int) tf->file.name.len,
|
||||
tf->file.name.data);
|
||||
}
|
||||
|
||||
rb->temp_file = NULL;
|
||||
}
|
||||
|
||||
if (body.len == 0) {
|
||||
|
||||
if (rb->bufs) {
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
for (cl = rb->bufs; cl; cl = cl->next) {
|
||||
if (cl->buf->tag == llcf->tag && cl->buf->temporary) {
|
||||
|
||||
dd("free old request body buffer: size:%d",
|
||||
(int) ngx_buf_size(cl->buf));
|
||||
|
||||
ngx_pfree(r->pool, cl->buf->start);
|
||||
cl->buf->tag = (ngx_buf_tag_t) NULL;
|
||||
cl->buf->temporary = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rb->bufs = NULL;
|
||||
rb->buf = NULL;
|
||||
|
||||
dd("request body is set to empty string");
|
||||
goto set_header;
|
||||
}
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (rb->bufs) {
|
||||
|
||||
for (cl = rb->bufs; cl; cl = cl->next) {
|
||||
if (cl->buf->tag == llcf->tag && cl->buf->temporary) {
|
||||
dd("free old request body buffer: size:%d",
|
||||
(int) ngx_buf_size(cl->buf));
|
||||
|
||||
ngx_pfree(r->pool, cl->buf->start);
|
||||
cl->buf->tag = (ngx_buf_tag_t) NULL;
|
||||
cl->buf->temporary = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rb->bufs->next = NULL;
|
||||
|
||||
b = rb->bufs->buf;
|
||||
|
||||
ngx_memzero(b, sizeof(ngx_buf_t));
|
||||
|
||||
b->temporary = 1;
|
||||
b->tag = llcf->tag;
|
||||
|
||||
b->start = ngx_palloc(r->pool, body.len);
|
||||
if (b->start == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
b->end = b->start + body.len;
|
||||
|
||||
b->pos = b->start;
|
||||
b->last = ngx_copy(b->pos, body.data, body.len);
|
||||
|
||||
} else {
|
||||
|
||||
rb->bufs = ngx_alloc_chain_link(r->pool);
|
||||
if (rb->bufs == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
rb->bufs->next = NULL;
|
||||
|
||||
b = ngx_create_temp_buf(r->pool, body.len);
|
||||
b->tag = llcf->tag;
|
||||
b->last = ngx_copy(b->pos, body.data, body.len);
|
||||
|
||||
rb->bufs->buf = b;
|
||||
rb->buf = b;
|
||||
}
|
||||
|
||||
set_header:
|
||||
|
||||
/* override input header Content-Length */
|
||||
|
||||
value.data = ngx_palloc(r->pool, NGX_SIZE_T_LEN);
|
||||
if (value.data == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
|
||||
value.len = ngx_sprintf(value.data, "%uz", body.len) - value.data;
|
||||
|
||||
dd("setting request Content-Length to %.*s (%d)",
|
||||
(int) value.len, value.data, (int) body.len);
|
||||
|
||||
r->headers_in.content_length_n = body.len;
|
||||
|
||||
if (r->headers_in.content_length) {
|
||||
r->headers_in.content_length->value.data = value.data;
|
||||
r->headers_in.content_length->value.len = value.len;
|
||||
|
||||
} else {
|
||||
|
||||
ngx_str_set(&key, "Content-Length");
|
||||
|
||||
rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */);
|
||||
if (rc != NGX_OK) {
|
||||
return luaL_error(L, "failed to reset the Content-Length "
|
||||
"input header");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_pool_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)
|
||||
{
|
||||
ngx_pool_cleanup_t *c;
|
||||
ngx_pool_cleanup_file_t *cf;
|
||||
|
||||
for (c = p->cleanup; c; c = c->next) {
|
||||
if (c->handler == ngx_pool_cleanup_file
|
||||
|| c->handler == ngx_pool_delete_file)
|
||||
{
|
||||
|
||||
cf = c->data;
|
||||
|
||||
if (cf->fd == fd) {
|
||||
c->handler(cf);
|
||||
c->handler = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_set_body_file(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
int n;
|
||||
ngx_http_request_body_t *rb;
|
||||
ngx_temp_file_t *tf;
|
||||
ngx_buf_t *b;
|
||||
ngx_str_t name;
|
||||
ngx_int_t rc;
|
||||
int clean;
|
||||
ngx_open_file_info_t of;
|
||||
ngx_str_t key, value;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
ngx_pool_cleanup_file_t *clnf;
|
||||
ngx_err_t err;
|
||||
ngx_chain_t *cl;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n != 1 && n != 2) {
|
||||
return luaL_error(L, "expecting 1 or 2 arguments but seen %d", n);
|
||||
}
|
||||
|
||||
name.data = (u_char *) luaL_checklstring(L, 1, &name.len);
|
||||
|
||||
if (n == 2) {
|
||||
luaL_checktype(L, 2, LUA_TBOOLEAN);
|
||||
clean = lua_toboolean(L, 2);
|
||||
|
||||
} else {
|
||||
clean = 0;
|
||||
}
|
||||
|
||||
dd("clean: %d", (int) clean);
|
||||
|
||||
lua_getglobal(L, GLOBALS_SYMBOL_REQUEST);
|
||||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (r->request_body == NULL) {
|
||||
|
||||
#if 1
|
||||
rc = ngx_http_discard_request_body(r);
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return luaL_error(L, "failed to discard request body");
|
||||
}
|
||||
#endif
|
||||
|
||||
rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
|
||||
if (rb == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
|
||||
r->request_body = rb;
|
||||
|
||||
} else {
|
||||
rb = r->request_body;
|
||||
}
|
||||
|
||||
/* clean up existing r->request_body->bufs (if any) */
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (rb->bufs) {
|
||||
dd("XXX reusing buf");
|
||||
|
||||
for (cl = rb->bufs; cl; cl = cl->next) {
|
||||
if (cl->buf->tag == llcf->tag && cl->buf->temporary) {
|
||||
dd("free old request body buffer: size:%d",
|
||||
(int) ngx_buf_size(cl->buf));
|
||||
|
||||
ngx_pfree(r->pool, cl->buf->start);
|
||||
cl->buf->tag = (ngx_buf_tag_t) NULL;
|
||||
cl->buf->temporary = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rb->bufs->next = NULL;
|
||||
b = rb->bufs->buf;
|
||||
|
||||
ngx_memzero(b, sizeof(ngx_buf_t));
|
||||
|
||||
b->tag = llcf->tag;
|
||||
|
||||
} else {
|
||||
|
||||
dd("XXX creating new buf");
|
||||
|
||||
rb->bufs = ngx_alloc_chain_link(r->pool);
|
||||
if (rb->bufs == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
rb->bufs->next = NULL;
|
||||
|
||||
b = ngx_calloc_buf(r->pool);
|
||||
if (b == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
|
||||
b->tag = llcf->tag;
|
||||
|
||||
rb->bufs->buf = b;
|
||||
rb->buf = b;
|
||||
}
|
||||
|
||||
b->last_in_chain = 1;
|
||||
|
||||
/* just make r->request_body->temp_file a bare stub */
|
||||
|
||||
tf = rb->temp_file;
|
||||
|
||||
if (tf) {
|
||||
if (tf->file.fd != NGX_INVALID_FILE) {
|
||||
|
||||
dd("cleaning temp file %.*s", (int) tf->file.name.len,
|
||||
tf->file.name.data);
|
||||
|
||||
ngx_http_lua_pool_cleanup_file(r->pool, tf->file.fd);
|
||||
|
||||
ngx_memzero(tf, sizeof(ngx_temp_file_t));
|
||||
|
||||
tf->file.fd = NGX_INVALID_FILE;
|
||||
|
||||
dd("temp file cleaned: %.*s", (int) tf->file.name.len,
|
||||
tf->file.name.data);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
|
||||
if (tf == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
|
||||
tf->file.fd = NGX_INVALID_FILE;
|
||||
rb->temp_file = tf;
|
||||
}
|
||||
|
||||
/* read the file info and construct an in-file buf */
|
||||
|
||||
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
|
||||
|
||||
if (ngx_http_lua_open_and_stat_file(name.data, &of, r->connection->log)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return luaL_error(L, "%s \"%s\" failed", of.failed, name.data);
|
||||
}
|
||||
|
||||
dd("XXX new body file fd: %d", of.fd);
|
||||
|
||||
tf->file.fd = of.fd;
|
||||
tf->file.name = name;
|
||||
tf->file.log = r->connection->log;
|
||||
|
||||
/* FIXME we should not always set directio here */
|
||||
tf->file.directio = 1;
|
||||
|
||||
if (of.size == 0) {
|
||||
if (clean) {
|
||||
if (ngx_delete_file(name.data) == NGX_FILE_ERROR) {
|
||||
err = ngx_errno;
|
||||
|
||||
if (err != NGX_ENOENT) {
|
||||
ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
|
||||
ngx_delete_file_n " \"%s\" failed",
|
||||
name.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_close_file(of.fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", name.data);
|
||||
}
|
||||
|
||||
r->request_body->bufs = NULL;
|
||||
r->request_body->buf = NULL;
|
||||
|
||||
goto set_header;
|
||||
}
|
||||
|
||||
/* register file cleanup hook */
|
||||
|
||||
cln = ngx_pool_cleanup_add(r->pool,
|
||||
sizeof(ngx_pool_cleanup_file_t));
|
||||
|
||||
if (cln == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
|
||||
cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
|
||||
clnf = cln->data;
|
||||
|
||||
clnf->fd = of.fd;
|
||||
clnf->name = name.data;
|
||||
clnf->log = r->pool->log;
|
||||
|
||||
b->file = &tf->file;
|
||||
if (b->file == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
dd("XXX file size: %d", (int) of.size);
|
||||
|
||||
b->file_pos = 0;
|
||||
b->file_last = of.size;
|
||||
|
||||
b->in_file = 1;
|
||||
|
||||
dd("buf file: %p, f:%u", b->file, b->in_file);
|
||||
|
||||
set_header:
|
||||
/* override input header Content-Length */
|
||||
|
||||
value.data = ngx_palloc(r->pool, NGX_OFF_T_LEN);
|
||||
if (value.data == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
|
||||
value.len = ngx_sprintf(value.data, "%O", of.size) - value.data;
|
||||
|
||||
r->headers_in.content_length_n = of.size;
|
||||
|
||||
if (r->headers_in.content_length) {
|
||||
r->headers_in.content_length->value.data = value.data;
|
||||
r->headers_in.content_length->value.len = value.len;
|
||||
|
||||
} else {
|
||||
ngx_str_set(&key, "Content-Length");
|
||||
|
||||
rc = ngx_http_lua_set_input_header(r, key, value, 1 /* override */);
|
||||
if (rc != NGX_OK) {
|
||||
return luaL_error(L, "failed to reset the Content-Length "
|
||||
"input header");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef NGX_HTTP_LUA_REQ_BODY_H
|
||||
#define NGX_HTTP_LUA_REQ_BODY_H
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_req_body_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* NGX_HTTP_LUA_REQ_BODY_H */
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
/* vim:set ft=c ts=4 sw=4 et fdm=marker: */
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_http_lua_rewriteby.h"
|
||||
|
@ -9,140 +12,8 @@
|
|||
#include "ngx_http_lua_cache.h"
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
int cc_ref;
|
||||
lua_State *cc;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_cleanup_t *cln;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
cc = ngx_http_lua_new_thread(r, L, &cc_ref);
|
||||
|
||||
if (cc == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"lua: failed to create new coroutine to handle request");
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* move code closure to new coroutine */
|
||||
lua_xmove(L, cc, 1);
|
||||
|
||||
/* set closure's env table to new coroutine's globals table */
|
||||
lua_pushvalue(cc, LUA_GLOBALSINDEX);
|
||||
lua_setfenv(cc, -2);
|
||||
|
||||
/* save reference of code to ease forcing stopping */
|
||||
lua_pushvalue(cc, -1);
|
||||
lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE);
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
lua_pushlightuserdata(cc, r);
|
||||
lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ initialize request context */
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_reset_ctx(r, L, ctx);
|
||||
|
||||
ctx->entered_rewrite_phase = 1;
|
||||
|
||||
ctx->cc = cc;
|
||||
ctx->cc_ref = cc_ref;
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ register request cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_http_cleanup_add(r, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup;
|
||||
cln->data = r;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
return ngx_http_lua_run_thread(L, r, ctx, 0);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
char *err;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (ngx_http_complex_value(r, &llcf->rewrite_src, &eval_src) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
L = lmcf->lua;
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->rewrite_src_key,
|
||||
&err, llcf->enable_code_cache ? 1 : 0);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
if (err == NULL) {
|
||||
err = "unknown error";
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"Failed to load Lua inlined code: %s", err);
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
assert(lua_isfunction(L, -1));
|
||||
|
||||
rc = ngx_http_lua_rewrite_by_chunk(L, r);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (rc >= NGX_HTTP_OK && rc < NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
static ngx_int_t ngx_http_lua_rewrite_by_chunk(lua_State *L,
|
||||
ngx_http_request_t *r);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
|
@ -153,6 +24,10 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r)
|
|||
ngx_int_t rc;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
if (r->uri_changed) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua rewrite handler, uri \"%V\"", &r->uri);
|
||||
|
||||
|
@ -233,10 +108,11 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r)
|
|||
return rc;
|
||||
}
|
||||
|
||||
if (llcf->force_read_body &&
|
||||
! ctx->read_body_done &&
|
||||
((r->method & NGX_HTTP_POST) || (r->method & NGX_HTTP_PUT)))
|
||||
{
|
||||
if (llcf->force_read_body && !ctx->read_body_done) {
|
||||
r->request_body_in_single_buf = 1;
|
||||
r->request_body_in_persistent_file = 1;
|
||||
r->request_body_in_clean_file = 1;
|
||||
|
||||
rc = ngx_http_read_client_request_body(r,
|
||||
ngx_http_lua_generic_phase_post_read);
|
||||
|
||||
|
@ -264,7 +140,7 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r)
|
|||
ngx_http_lua_loc_conf_t *llcf;
|
||||
char *err;
|
||||
|
||||
dd("HERE");
|
||||
dd("rewrite by lua inline");
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
@ -287,9 +163,123 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r)
|
|||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
rc = ngx_http_lua_rewrite_by_chunk(L, r);
|
||||
return ngx_http_lua_rewrite_by_chunk(L, r);
|
||||
}
|
||||
|
||||
dd("rewrite by chunk returns %d", (int) rc);
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
char *err;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (ngx_http_complex_value(r, &llcf->rewrite_src, &eval_src) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
L = lmcf->lua;
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(L, script_path, llcf->rewrite_src_key,
|
||||
&err, llcf->enable_code_cache ? 1 : 0);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
if (err == NULL) {
|
||||
err = "unknown error";
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"Failed to load Lua file code: %s", err);
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return ngx_http_lua_rewrite_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
int cc_ref;
|
||||
lua_State *cc;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_cleanup_t *cln;
|
||||
ngx_int_t rc;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
cc = ngx_http_lua_new_thread(r, L, &cc_ref);
|
||||
|
||||
if (cc == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"lua: failed to create new coroutine to handle request");
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* move code closure to new coroutine */
|
||||
lua_xmove(L, cc, 1);
|
||||
|
||||
/* set closure's env table to new coroutine's globals table */
|
||||
lua_pushvalue(cc, LUA_GLOBALSINDEX);
|
||||
lua_setfenv(cc, -2);
|
||||
|
||||
/* save reference of code to ease forcing stopping */
|
||||
lua_pushvalue(cc, -1);
|
||||
lua_setglobal(cc, GLOBALS_SYMBOL_RUNCODE);
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
lua_pushlightuserdata(cc, r);
|
||||
lua_setglobal(cc, GLOBALS_SYMBOL_REQUEST);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ initialize request context */
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_reset_ctx(r, L, ctx);
|
||||
|
||||
ctx->entered_rewrite_phase = 1;
|
||||
|
||||
ctx->cc = cc;
|
||||
ctx->cc_ref = cc_ref;
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ register request cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_http_cleanup_add(r, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup;
|
||||
cln->data = r;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
rc = ngx_http_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
|
@ -300,15 +290,14 @@ ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
return NGX_OK;
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
if (rc >= NGX_HTTP_OK && rc < NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
dd("returning declined...");
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
/* vim:set ft=c ts=4 sw=4 et fdm=marker: */
|
||||
|
||||
#ifndef NGX_HTTP_LUA_REWRITE_BY_H__
|
||||
#define NGX_HTTP_LUA_REWRITE_BY_H__
|
||||
#ifndef NGX_HTTP_LUA_REWRITEBY_H
|
||||
#define NGX_HTTP_LUA_REWRITEBY_H
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_rewrite_handler(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r);
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* NGX_HTTP_LUA_REWRITEBY_H */
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs,
|
|||
ngx_http_lua_inject_time_api(L);
|
||||
ngx_http_lua_inject_string_api(L);
|
||||
ngx_http_lua_inject_variable_api(L);
|
||||
ngx_http_lua_inject_req_api(L);
|
||||
ngx_http_lua_inject_req_api_no_io(L);
|
||||
ngx_http_lua_inject_arg_api(L, nargs, args);
|
||||
#if (NGX_PCRE)
|
||||
ngx_http_lua_inject_regex_api(L);
|
||||
|
|
|
@ -743,6 +743,9 @@ ngx_http_lua_handle_subreq_responses(ngx_http_request_t *r,
|
|||
|
||||
u_char buf[sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1];
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua handle subrequest responses");
|
||||
|
||||
for (index = 0; index < ctx->nsubreqs; index++) {
|
||||
dd("summary: reqs %d, subquery %d, waiting %d, req %.*s",
|
||||
(int) ctx->nsubreqs,
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
#include "ngx_http_lua_uri.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
|
||||
static int ngx_http_lua_ngx_req_set_uri(lua_State *L);
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_req_uri_api(lua_State *L)
|
||||
{
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_set_uri);
|
||||
lua_setfield(L, -2, "set_uri");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_set_uri(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
size_t len;
|
||||
u_char *p;
|
||||
int n;
|
||||
int jump = 0;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n != 1 && n != 2) {
|
||||
return luaL_error(L, "expecting 1 argument but seen %d", n);
|
||||
}
|
||||
|
||||
lua_getglobal(L, GLOBALS_SYMBOL_REQUEST);
|
||||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (n == 2) {
|
||||
luaL_checktype(L, 2, LUA_TBOOLEAN);
|
||||
jump = lua_toboolean(L, 2);
|
||||
}
|
||||
|
||||
p = (u_char *) luaL_checklstring(L, 1, &len);
|
||||
|
||||
if (len == 0) {
|
||||
return luaL_error(L, "attempt to use zero-length uri");
|
||||
}
|
||||
|
||||
r->uri.data = ngx_palloc(r->pool, len);
|
||||
ngx_memcpy(r->uri.data, p, len);
|
||||
|
||||
r->uri.len = len;
|
||||
|
||||
r->internal = 1;
|
||||
r->valid_unparsed_uri = 0;
|
||||
|
||||
ngx_http_set_exten(r);
|
||||
|
||||
if (jump) {
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
#if defined(DDEBUG) && DDEBUG
|
||||
if (ctx) {
|
||||
dd("rewrite: %d, access: %d, content: %d",
|
||||
(int) ctx->entered_rewrite_phase,
|
||||
(int) ctx->entered_access_phase,
|
||||
(int) ctx->entered_content_phase);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ctx && ctx->entered_rewrite_phase
|
||||
&& !ctx->entered_access_phase
|
||||
&& !ctx->entered_content_phase)
|
||||
{
|
||||
r->uri_changed = 1;
|
||||
return lua_yield(L, 0);
|
||||
}
|
||||
|
||||
return luaL_error(L, "attempt to call ngx.req.set_uri to do "
|
||||
"location jump in contexts other than rewrite_by_lua and "
|
||||
"rewrite_by_lua_file");
|
||||
}
|
||||
|
||||
r->valid_location = 0;
|
||||
r->uri_changed = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef NGX_HTTP_LUA_URI_H
|
||||
#define NGX_HTTP_LUA_URI_H
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_req_uri_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* NGX_HTTP_LUA_URI_H */
|
||||
|
|
@ -12,6 +12,8 @@
|
|||
#include "ngx_http_lua_pcrefix.h"
|
||||
#include "ngx_http_lua_regex.h"
|
||||
#include "ngx_http_lua_args.h"
|
||||
#include "ngx_http_lua_uri.h"
|
||||
#include "ngx_http_lua_req_body.h"
|
||||
#include "ngx_http_lua_headers.h"
|
||||
#include "ngx_http_lua_output.h"
|
||||
#include "ngx_http_lua_time.h"
|
||||
|
@ -36,6 +38,8 @@ static ngx_int_t ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r,
|
|||
ngx_http_lua_ctx_t *ctx, int cc_ref);
|
||||
static ngx_int_t ngx_http_lua_handle_exit(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, int cc_ref);
|
||||
static ngx_int_t ngx_http_lua_handle_rewrite_jump(lua_State *L,
|
||||
ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int cc_ref);
|
||||
|
||||
|
||||
#ifndef LUA_PATH_SEP
|
||||
|
@ -631,6 +635,7 @@ ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L,
|
|||
|
||||
ctx->entered_rewrite_phase = 0;
|
||||
ctx->entered_access_phase = 0;
|
||||
ctx->entered_content_phase = 0;
|
||||
|
||||
ctx->exit_code = 0;
|
||||
ctx->exited = 0;
|
||||
|
@ -652,8 +657,6 @@ ngx_http_lua_generic_phase_post_read(ngx_http_request_t *r)
|
|||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua post read for rewrite/access phases");
|
||||
|
||||
r->read_event_handler = ngx_http_request_empty_handler;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
ctx->read_body_done = 1;
|
||||
|
@ -757,6 +760,8 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r,
|
|||
ngx_http_lua_pcre_malloc_init(r->pool);
|
||||
#endif
|
||||
|
||||
dd("calling lua_resume: vm %p, nret %d", cc, (int) nret);
|
||||
|
||||
/* run code */
|
||||
rv = lua_resume(cc, nret);
|
||||
|
||||
|
@ -776,6 +781,10 @@ ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r,
|
|||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua thread yielded");
|
||||
|
||||
if (r->uri_changed) {
|
||||
return ngx_http_lua_handle_rewrite_jump(L, r, ctx, cc_ref);
|
||||
}
|
||||
|
||||
if (ctx->exited) {
|
||||
return ngx_http_lua_handle_exit(L, r, ctx, cc_ref);
|
||||
}
|
||||
|
@ -867,6 +876,7 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r)
|
|||
ngx_int_t rc;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
int nret = 0;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua run write event handler");
|
||||
|
@ -902,6 +912,13 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r)
|
|||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (ctx->waiting_more_body && !ctx->req_read_body_done) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua write event handler waiting for more request body data");
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
dd("waiting: %d, done: %d", (int) ctx->waiting,
|
||||
ctx->done);
|
||||
|
||||
|
@ -939,27 +956,60 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r)
|
|||
return NGX_DONE;
|
||||
}
|
||||
|
||||
ctx->done = 0;
|
||||
dd("req read body done: %d", (int) ctx->req_read_body_done);
|
||||
|
||||
dd("nsubreqs: %d", (int) ctx->nsubreqs);
|
||||
if (ctx->req_read_body_done) {
|
||||
dd("turned off req read body done");
|
||||
|
||||
ngx_http_lua_handle_subreq_responses(r, ctx);
|
||||
ctx->req_read_body_done = 0;
|
||||
|
||||
dd("free sr_statues/headers/bodies memory ASAP");
|
||||
nret = 0;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua read req body done, resuming lua thread");
|
||||
|
||||
goto run;
|
||||
|
||||
} else if (ctx->done) {
|
||||
ctx->done = 0;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua run subrequests done, resuming lua thread");
|
||||
|
||||
dd("nsubreqs: %d", (int) ctx->nsubreqs);
|
||||
|
||||
ngx_http_lua_handle_subreq_responses(r, ctx);
|
||||
|
||||
dd("free sr_statues/headers/bodies memory ASAP");
|
||||
|
||||
#if 1
|
||||
ngx_pfree(r->pool, ctx->sr_statuses);
|
||||
ngx_pfree(r->pool, ctx->sr_statuses);
|
||||
|
||||
ctx->sr_statuses = NULL;
|
||||
ctx->sr_headers = NULL;
|
||||
ctx->sr_bodies = NULL;
|
||||
ctx->sr_statuses = NULL;
|
||||
ctx->sr_headers = NULL;
|
||||
ctx->sr_bodies = NULL;
|
||||
#endif
|
||||
|
||||
nret = ctx->nsubreqs;
|
||||
|
||||
goto run;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"useless lua write event handler");
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, NGX_DONE);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
run:
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
dd("about to run thread for %.*s...", (int) r->uri.len, r->uri.data);
|
||||
|
||||
rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, ctx->nsubreqs);
|
||||
rc = ngx_http_lua_run_thread(lmcf->lua, r, ctx, nret);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua run thread returned %d", rc);
|
||||
|
@ -969,11 +1019,8 @@ ngx_http_lua_wev_handler(ngx_http_request_t *r)
|
|||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_finalize_request(r, rc);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
ngx_http_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
dd("entered content phase: %d", (int) ctx->entered_content_phase);
|
||||
|
@ -1411,6 +1458,23 @@ done:
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_req_api_no_io(lua_State *L)
|
||||
{
|
||||
/* ngx.req table */
|
||||
|
||||
lua_newtable(L); /* .req */
|
||||
|
||||
ngx_http_lua_inject_req_header_api(L);
|
||||
|
||||
ngx_http_lua_inject_req_uri_api(L);
|
||||
|
||||
ngx_http_lua_inject_req_args_api(L);
|
||||
|
||||
lua_setfield(L, -2, "req");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_req_api(lua_State *L)
|
||||
{
|
||||
|
@ -1420,8 +1484,12 @@ ngx_http_lua_inject_req_api(lua_State *L)
|
|||
|
||||
ngx_http_lua_inject_req_header_api(L);
|
||||
|
||||
ngx_http_lua_inject_req_uri_api(L);
|
||||
|
||||
ngx_http_lua_inject_req_args_api(L);
|
||||
|
||||
ngx_http_lua_inject_req_body_api(L);
|
||||
|
||||
lua_setfield(L, -2, "req");
|
||||
}
|
||||
|
||||
|
@ -1450,20 +1518,26 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r,
|
|||
|
||||
r->write_event_handler = ngx_http_request_empty_handler;
|
||||
|
||||
#if 1
|
||||
/* clear the modules contexts */
|
||||
ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
|
||||
#endif
|
||||
|
||||
rc = ngx_http_named_location(r, &ctx->exec_uri);
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (! ctx->entered_content_phase &&
|
||||
r != r->connection->data)
|
||||
{
|
||||
#if 0
|
||||
if (!ctx->entered_content_phase) {
|
||||
/* XXX ensure the main request ref count
|
||||
* is decreased because the current
|
||||
* request will be quit */
|
||||
r->main->count--;
|
||||
dd("XXX decrement main count: c:%d", (int) r->main->count);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
@ -1486,14 +1560,15 @@ ngx_http_lua_handle_exec(lua_State *L, ngx_http_request_t *r,
|
|||
|
||||
dd("XXYY HERE %d\n", (int) r->main->count);
|
||||
|
||||
if (! ctx->entered_content_phase &&
|
||||
r != r->connection->data)
|
||||
{
|
||||
#if 0
|
||||
if (!ctx->entered_content_phase) {
|
||||
/* XXX ensure the main request ref count
|
||||
* is decreased because the current
|
||||
* request will be quit */
|
||||
dd("XXX decrement main count");
|
||||
r->main->count--;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
@ -1637,4 +1712,126 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L,
|
|||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_handle_rewrite_jump(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, int cc_ref)
|
||||
{
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua thread aborting request with URI rewrite jump: \"%V?%V\"",
|
||||
&r->uri, &r->args);
|
||||
|
||||
ngx_http_lua_del_thread(r, L, cc_ref, 1 /* force quit */);
|
||||
ctx->cc_ref = LUA_NOREF;
|
||||
ngx_http_lua_request_cleanup(r);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_open_and_stat_file(u_char *name, ngx_open_file_info_t *of,
|
||||
ngx_log_t *log)
|
||||
{
|
||||
ngx_fd_t fd;
|
||||
ngx_file_info_t fi;
|
||||
|
||||
if (of->fd != NGX_INVALID_FILE) {
|
||||
|
||||
if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
|
||||
of->failed = ngx_file_info_n;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (of->uniq == ngx_file_uniq(&fi)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
} else if (of->test_dir) {
|
||||
|
||||
if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) {
|
||||
of->failed = ngx_file_info_n;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (ngx_is_dir(&fi)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!of->log) {
|
||||
|
||||
/*
|
||||
* Use non-blocking open() not to hang on FIFO files, etc.
|
||||
* This flag has no effect on a regular files.
|
||||
*/
|
||||
|
||||
fd = ngx_open_file(name, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
|
||||
NGX_FILE_OPEN, 0);
|
||||
|
||||
} else {
|
||||
fd = ngx_open_file(name, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN,
|
||||
NGX_FILE_DEFAULT_ACCESS);
|
||||
}
|
||||
|
||||
if (fd == NGX_INVALID_FILE) {
|
||||
of->failed = ngx_open_file_n;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
|
||||
ngx_fd_info_n " \"%s\" failed", name);
|
||||
|
||||
if (ngx_close_file(fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", name);
|
||||
}
|
||||
|
||||
of->fd = NGX_INVALID_FILE;
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_is_dir(&fi)) {
|
||||
if (ngx_close_file(fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", name);
|
||||
}
|
||||
|
||||
of->fd = NGX_INVALID_FILE;
|
||||
|
||||
} else {
|
||||
of->fd = fd;
|
||||
|
||||
if (of->directio <= ngx_file_size(&fi)) {
|
||||
if (ngx_directio_on(fd) == NGX_FILE_ERROR) {
|
||||
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
|
||||
ngx_directio_on_n " \"%s\" failed", name);
|
||||
|
||||
} else {
|
||||
of->is_directio = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
of->uniq = ngx_file_uniq(&fi);
|
||||
of->mtime = ngx_file_mtime(&fi);
|
||||
of->size = ngx_file_size(&fi);
|
||||
of->fs_size = ngx_file_fs_size(&fi);
|
||||
of->is_dir = ngx_is_dir(&fi);
|
||||
of->is_file = ngx_is_file(&fi);
|
||||
of->is_link = ngx_is_link(&fi);
|
||||
of->is_exec = ngx_is_exec(&fi);
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
failed:
|
||||
|
||||
of->fd = NGX_INVALID_FILE;
|
||||
of->err = ngx_errno;
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,39 +18,65 @@
|
|||
|
||||
|
||||
lua_State * ngx_http_lua_new_state(ngx_conf_t *cf,
|
||||
ngx_http_lua_main_conf_t *lmcf);
|
||||
ngx_http_lua_main_conf_t *lmcf);
|
||||
|
||||
lua_State * ngx_http_lua_new_thread(ngx_http_request_t *r, lua_State *l,
|
||||
int *ref);
|
||||
int *ref);
|
||||
|
||||
void ngx_http_lua_del_thread(ngx_http_request_t *r, lua_State *l, int ref,
|
||||
int force_quit);
|
||||
int force_quit);
|
||||
|
||||
ngx_int_t ngx_http_lua_has_inline_var(ngx_str_t *s);
|
||||
|
||||
u_char * ngx_http_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len);
|
||||
|
||||
ngx_int_t ngx_http_lua_send_header_if_needed(ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx);
|
||||
ngx_http_lua_ctx_t *ctx);
|
||||
|
||||
ngx_int_t ngx_http_lua_send_chain_link(ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, ngx_chain_t *cl);
|
||||
ngx_http_lua_ctx_t *ctx, ngx_chain_t *cl);
|
||||
|
||||
void ngx_http_lua_discard_bufs(ngx_pool_t *pool, ngx_chain_t *in);
|
||||
|
||||
ngx_int_t ngx_http_lua_add_copy_chain(ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, ngx_chain_t **chain, ngx_chain_t *in);
|
||||
ngx_http_lua_ctx_t *ctx, ngx_chain_t **chain, ngx_chain_t *in);
|
||||
|
||||
void ngx_http_lua_reset_ctx(ngx_http_request_t *r, lua_State *L,
|
||||
ngx_http_lua_ctx_t *ctx);
|
||||
ngx_http_lua_ctx_t *ctx);
|
||||
|
||||
void ngx_http_lua_generic_phase_post_read(ngx_http_request_t *r);
|
||||
|
||||
void ngx_http_lua_request_cleanup(void *data);
|
||||
|
||||
ngx_int_t ngx_http_lua_run_thread(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, int nret);
|
||||
ngx_http_lua_ctx_t *ctx, int nret);
|
||||
|
||||
ngx_int_t ngx_http_lua_wev_handler(ngx_http_request_t *r);
|
||||
|
||||
u_char * ngx_http_lua_digest_hex(u_char *dest, const u_char *buf,
|
||||
int buf_len);
|
||||
int buf_len);
|
||||
|
||||
void ngx_http_lua_dump_postponed(ngx_http_request_t *r);
|
||||
|
||||
ngx_int_t ngx_http_lua_flush_postponed_outputs(ngx_http_request_t *r);
|
||||
|
||||
void ngx_http_lua_set_multi_value_table(lua_State *L, int index);
|
||||
|
||||
void ngx_http_lua_unescape_uri(u_char **dst, u_char **src, size_t size,
|
||||
ngx_uint_t type);
|
||||
ngx_uint_t type);
|
||||
|
||||
uintptr_t ngx_http_lua_escape_uri(u_char *dst, u_char *src,
|
||||
size_t size, ngx_uint_t type);
|
||||
size_t size, ngx_uint_t type);
|
||||
|
||||
void ngx_http_lua_inject_req_api(lua_State *L);
|
||||
|
||||
void ngx_http_lua_inject_req_api_no_io(lua_State *L);
|
||||
|
||||
void ngx_http_lua_process_args_option(ngx_http_request_t *r,
|
||||
lua_State *L, int table, ngx_str_t *args);
|
||||
lua_State *L, int table, ngx_str_t *args);
|
||||
|
||||
ngx_int_t ngx_http_lua_open_and_stat_file(u_char *name,
|
||||
ngx_open_file_info_t *of, ngx_log_t *log);
|
||||
|
||||
|
||||
#endif /* NGX_HTTP_LUA_UTIL_H */
|
||||
|
|
|
@ -138,6 +138,8 @@ ngx_http_lua_var_set(lua_State *L)
|
|||
ngx_str_t name;
|
||||
ngx_uint_t hash;
|
||||
ngx_http_request_t *r;
|
||||
int value_type;
|
||||
const char *msg;
|
||||
|
||||
lua_getglobal(L, GLOBALS_SYMBOL_REQUEST);
|
||||
r = lua_touserdata(L, -1);
|
||||
|
@ -167,15 +169,35 @@ ngx_http_lua_var_set(lua_State *L)
|
|||
|
||||
/* we read the variable new value */
|
||||
|
||||
p = (u_char *) luaL_checklstring(L, 3, &len);
|
||||
value_type = lua_type(L, 3);
|
||||
switch (value_type) {
|
||||
case LUA_TNUMBER:
|
||||
case LUA_TSTRING:
|
||||
p = (u_char *) luaL_checklstring(L, 3, &len);
|
||||
|
||||
val = ngx_palloc(r->pool, len);
|
||||
if (val == NULL) {
|
||||
return luaL_error(L, "memory allocation erorr");
|
||||
val = ngx_palloc(r->pool, len);
|
||||
if (val == NULL) {
|
||||
return luaL_error(L, "memory allocation erorr");
|
||||
}
|
||||
|
||||
ngx_memcpy(val, p, len);
|
||||
|
||||
break;
|
||||
|
||||
case LUA_TNIL:
|
||||
/* undef the variable */
|
||||
|
||||
val = NULL;
|
||||
len = 0;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
msg = lua_pushfstring(L, "string, number, or nil expected, "
|
||||
"but got %s", lua_typename(L, value_type));
|
||||
return luaL_argerror(L, 1, msg);
|
||||
}
|
||||
|
||||
ngx_memcpy(val, p, len);
|
||||
|
||||
/* we fetch the variable itself */
|
||||
|
||||
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
|
||||
|
@ -188,17 +210,29 @@ ngx_http_lua_var_set(lua_State *L)
|
|||
}
|
||||
|
||||
if (v->set_handler) {
|
||||
|
||||
dd("set variables with set_handler");
|
||||
|
||||
vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
|
||||
if (vv == NULL) {
|
||||
return luaL_error(L, "out of memory");
|
||||
}
|
||||
|
||||
vv->valid = 1;
|
||||
vv->not_found = 0;
|
||||
vv->no_cacheable = 0;
|
||||
if (value_type == LUA_TNIL) {
|
||||
vv->valid = 0;
|
||||
vv->not_found = 1;
|
||||
vv->no_cacheable = 0;
|
||||
vv->data = NULL;
|
||||
vv->len = 0;
|
||||
|
||||
vv->data = val;
|
||||
vv->len = len;
|
||||
} else {
|
||||
vv->valid = 1;
|
||||
vv->not_found = 0;
|
||||
vv->no_cacheable = 0;
|
||||
|
||||
vv->data = val;
|
||||
vv->len = len;
|
||||
}
|
||||
|
||||
v->set_handler(r, vv, v->data);
|
||||
|
||||
|
@ -208,12 +242,24 @@ ngx_http_lua_var_set(lua_State *L)
|
|||
if (v->flags & NGX_HTTP_VAR_INDEXED) {
|
||||
vv = &r->variables[v->index];
|
||||
|
||||
vv->valid = 1;
|
||||
vv->not_found = 0;
|
||||
vv->no_cacheable = 0;
|
||||
dd("set indexed variable");
|
||||
|
||||
vv->data = val;
|
||||
vv->len = len;
|
||||
if (value_type == LUA_TNIL) {
|
||||
vv->valid = 0;
|
||||
vv->not_found = 1;
|
||||
vv->no_cacheable = 0;
|
||||
|
||||
vv->data = NULL;
|
||||
vv->len = 0;
|
||||
|
||||
} else {
|
||||
vv->valid = 1;
|
||||
vv->not_found = 0;
|
||||
vv->no_cacheable = 0;
|
||||
|
||||
vv->data = val;
|
||||
vv->len = len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
28
t/005-exit.t
28
t/005-exit.t
|
@ -439,3 +439,31 @@ GET /lua
|
|||
--- response_body
|
||||
hello
|
||||
|
||||
|
||||
|
||||
=== TEST 12: 501 Method Not Implemented
|
||||
--- config
|
||||
location /lua {
|
||||
content_by_lua '
|
||||
ngx.exit(501)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /lua
|
||||
--- error_code: 501
|
||||
--- response_body_like: 501 Method Not Implemented
|
||||
|
||||
|
||||
|
||||
=== TEST 13: 501 Method Not Implemented
|
||||
--- config
|
||||
location /lua {
|
||||
content_by_lua '
|
||||
ngx.exit(ngx.HTTP_METHOD_NOT_IMPLEMENTED)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /lua
|
||||
--- error_code: 501
|
||||
--- response_body_like: 501 Method Not Implemented
|
||||
|
||||
|
|
41
t/014-bugs.t
41
t/014-bugs.t
|
@ -5,10 +5,10 @@ use Test::Nginx::Socket;
|
|||
|
||||
#worker_connections(1014);
|
||||
#master_on();
|
||||
#log_level('warn');
|
||||
log_level('debug');
|
||||
|
||||
#repeat_each(120);
|
||||
#repeat_each(3);
|
||||
repeat_each(3);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 2 + 2);
|
||||
|
||||
|
@ -485,3 +485,40 @@ world
|
|||
nil
|
||||
nil
|
||||
|
||||
|
||||
|
||||
=== TEST 23: set special variables
|
||||
--- config
|
||||
location /main {
|
||||
#set_unescape_uri $cookie_a "hello";
|
||||
set $http_a "hello";
|
||||
content_by_lua '
|
||||
ngx.say(ngx.var.http_a)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /main
|
||||
--- response_body
|
||||
hello
|
||||
--- SKIP
|
||||
|
||||
|
||||
|
||||
=== TEST 24: set special variables
|
||||
--- config
|
||||
location /main {
|
||||
content_by_lua '
|
||||
dofile(ngx.var.realpath_root .. "/a.lua")
|
||||
';
|
||||
}
|
||||
location /echo {
|
||||
echo hi;
|
||||
}
|
||||
--- request
|
||||
GET /main
|
||||
--- user_files
|
||||
>>> a.lua
|
||||
ngx.location.capture("/echo")
|
||||
--- response_body
|
||||
--- SKIP
|
||||
|
||||
|
|
|
@ -64,8 +64,8 @@ Content-Type: text/html
|
|||
GET /read
|
||||
--- response_headers
|
||||
Content-Length: 3
|
||||
--- response_body
|
||||
Hello
|
||||
--- response_body chop
|
||||
Hel
|
||||
|
||||
|
||||
|
||||
|
@ -115,7 +115,7 @@ Hello
|
|||
--- request
|
||||
GET /read
|
||||
--- raw_response_headers_like chomp
|
||||
X-Foo: a\r\n.*?X-Foo: bc$
|
||||
X-Foo: a\r\n.*?X-Foo: bc\r\n
|
||||
--- response_body
|
||||
Hello
|
||||
|
||||
|
@ -186,7 +186,7 @@ Hello
|
|||
--- request
|
||||
GET /read
|
||||
--- raw_response_headers_like chomp
|
||||
X-Foo: a\r\n.*?X-Foo: abc$
|
||||
X-Foo: a\r\n.*?X-Foo: abc\r\n
|
||||
--- response_body
|
||||
Hello
|
||||
|
||||
|
@ -686,7 +686,7 @@ WWW-Authenticate: blah
|
|||
|
||||
|
||||
|
||||
=== TEST 34: set and clear the www-authenticate response header
|
||||
=== TEST 35: set and clear the www-authenticate response header
|
||||
--- config
|
||||
location /lua {
|
||||
content_by_lua '
|
||||
|
|
126
t/017-exec.t
126
t/017-exec.t
|
@ -420,3 +420,129 @@ GET /lua
|
|||
foo = 3
|
||||
bar = 4
|
||||
|
||||
|
||||
|
||||
=== TEST 19: jump to internal locations requires ctx cleared
|
||||
--- config
|
||||
location @proxy {
|
||||
rewrite_by_lua return;
|
||||
echo hello;
|
||||
}
|
||||
location /main {
|
||||
content_by_lua '
|
||||
ngx.exec("@proxy")
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /main
|
||||
--- response_body
|
||||
hello
|
||||
|
||||
|
||||
|
||||
=== TEST 20: exec + rewrite + named locations
|
||||
--- config
|
||||
location @proxy {
|
||||
rewrite_by_lua return;
|
||||
echo hello;
|
||||
}
|
||||
location /main {
|
||||
rewrite_by_lua '
|
||||
ngx.exec("@proxy")
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /main
|
||||
--- response_body
|
||||
hello
|
||||
|
||||
|
||||
|
||||
=== TEST 21: exec(named location) in subrequests
|
||||
--- config
|
||||
location /entry {
|
||||
echo_location /foo;
|
||||
echo_location /foo2;
|
||||
}
|
||||
location /foo {
|
||||
content_by_lua '
|
||||
ngx.exec("@bar")
|
||||
';
|
||||
}
|
||||
location /foo2 {
|
||||
content_by_lua '
|
||||
ngx.exec("@bar")
|
||||
';
|
||||
}
|
||||
|
||||
location @bar {
|
||||
proxy_pass http://127.0.0.1:$server_port/bar;
|
||||
}
|
||||
location /bar {
|
||||
echo hello;
|
||||
}
|
||||
--- request
|
||||
GET /entry
|
||||
--- response_body
|
||||
hello
|
||||
hello
|
||||
|
||||
|
||||
|
||||
=== TEST 22: exec(normal location) in subrequests
|
||||
--- config
|
||||
location /entry {
|
||||
echo_location /foo;
|
||||
echo_location /foo2;
|
||||
}
|
||||
location /foo {
|
||||
content_by_lua '
|
||||
ngx.exec("/baz")
|
||||
';
|
||||
}
|
||||
location /foo2 {
|
||||
content_by_lua '
|
||||
ngx.exec("/baz")
|
||||
';
|
||||
}
|
||||
|
||||
location /baz {
|
||||
proxy_pass http://127.0.0.1:$server_port/bar;
|
||||
}
|
||||
location /bar {
|
||||
echo hello;
|
||||
}
|
||||
--- request
|
||||
GET /entry
|
||||
--- response_body
|
||||
hello
|
||||
hello
|
||||
|
||||
|
||||
|
||||
=== TEST 23: content_by_lua + ngx.exec + subrequest capture
|
||||
--- config
|
||||
location /main {
|
||||
rewrite_by_lua '
|
||||
res = ngx.location.capture("/test_loc");
|
||||
ngx.print("hello, ", res.body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
location /test_loc {
|
||||
content_by_lua '
|
||||
ngx.exec("@proxy")
|
||||
';
|
||||
}
|
||||
location @proxy {
|
||||
#echo proxy;
|
||||
proxy_pass http://127.0.0.1:$server_port/foo;
|
||||
}
|
||||
location /foo {
|
||||
echo bah;
|
||||
}
|
||||
--- request
|
||||
GET /main
|
||||
--- response_body
|
||||
hello, bah
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@ use Test::Nginx::Socket;
|
|||
#master_process_enabled(1);
|
||||
#log_level('warn');
|
||||
|
||||
repeat_each(2);
|
||||
#repeat_each(2);
|
||||
#repeat_each(1);
|
||||
|
||||
plan tests => blocks() * repeat_each() * 3;
|
||||
plan tests => repeat_each() * (blocks() * 3 + 1);
|
||||
|
||||
#no_diff();
|
||||
#no_long_string();
|
||||
|
@ -128,3 +128,45 @@ GET /read
|
|||
--- response_body_like: 302 Found
|
||||
--- error_code: 302
|
||||
|
||||
|
||||
|
||||
=== TEST 7: default 302 (with uri args)
|
||||
--- config
|
||||
location /read {
|
||||
content_by_lua '
|
||||
ngx.redirect("http://www.taobao.com/foo?bar=3");
|
||||
ngx.say("hi")
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /read
|
||||
--- response_headers
|
||||
Location: http://www.taobao.com/foo?bar=3
|
||||
--- response_body_like: 302 Found
|
||||
--- error_code: 302
|
||||
|
||||
|
||||
|
||||
=== TEST 8: location.capture + ngx.redirect
|
||||
--- config
|
||||
location /echo {
|
||||
echo hello, world;
|
||||
}
|
||||
location /proxy {
|
||||
proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT/echo;
|
||||
}
|
||||
location /read {
|
||||
content_by_lua '
|
||||
ngx.location.capture("/proxy")
|
||||
ngx.location.capture("/proxy")
|
||||
ngx.redirect("/echo")
|
||||
ngx.exit(403)
|
||||
';
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["GET /read/1", "GET /read/2"]
|
||||
--- error_code eval
|
||||
[302, 302]
|
||||
--- response_body eval
|
||||
[qr/302 Found/, qr/302 Found/]
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use lib 'lib';
|
||||
use Test::Nginx::Socket;
|
||||
|
||||
#repeat_each(2);
|
||||
repeat_each(2);
|
||||
#repeat_each(1);
|
||||
|
||||
plan tests => blocks() * repeat_each() * 2;
|
||||
|
@ -249,8 +249,8 @@ hello
|
|||
}
|
||||
location /p{
|
||||
#content_by_lua '
|
||||
#local res = ngx.location.capture("/sub")
|
||||
#ngx.print(res.body)
|
||||
#local res = ngx.location.capture("/sub")
|
||||
#ngx.print(res.body)
|
||||
#';
|
||||
echo_location /sub;
|
||||
}
|
||||
|
@ -322,3 +322,60 @@ hello
|
|||
--- response_body
|
||||
hello
|
||||
|
||||
|
||||
|
||||
=== TEST 15: rewrite_by_lua + ngx.exec + subrequest capture
|
||||
--- config
|
||||
location /main {
|
||||
rewrite_by_lua '
|
||||
res = ngx.location.capture("/test_loc");
|
||||
ngx.print("hello, ", res.body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
location /test_loc {
|
||||
rewrite_by_lua '
|
||||
ngx.exec("@proxy")
|
||||
';
|
||||
}
|
||||
location @proxy {
|
||||
#echo proxy;
|
||||
proxy_pass http://127.0.0.1:$server_port/foo;
|
||||
}
|
||||
location /foo {
|
||||
echo bah;
|
||||
}
|
||||
--- request
|
||||
GET /main
|
||||
--- response_body
|
||||
hello, bah
|
||||
|
||||
|
||||
|
||||
=== TEST 16: rewrite_by_lua_file + ngx.exec + subrequest capture
|
||||
--- config
|
||||
location /main {
|
||||
rewrite_by_lua '
|
||||
res = ngx.location.capture("/test_loc");
|
||||
ngx.print("hello, ", res.body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
location /test_loc {
|
||||
rewrite_by_lua_file html/jump.lua;
|
||||
}
|
||||
location @proxy {
|
||||
#echo proxy;
|
||||
proxy_pass http://127.0.0.1:$server_port/foo;
|
||||
}
|
||||
location /foo {
|
||||
echo bah;
|
||||
}
|
||||
--- user_files
|
||||
>>> jump.lua
|
||||
ngx.exec("@proxy")
|
||||
--- request
|
||||
GET /main
|
||||
--- response_body
|
||||
hello, bah
|
||||
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
use lib 'lib';
|
||||
use Test::Nginx::Socket;
|
||||
|
||||
#worker_connections(1014);
|
||||
#master_process_enabled(1);
|
||||
#log_level('warn');
|
||||
|
||||
repeat_each(2);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 2);
|
||||
|
||||
#no_diff();
|
||||
#no_long_string();
|
||||
#master_on();
|
||||
#workers(2);
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: read buffered body
|
||||
--- config
|
||||
location = /test {
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.var.request_body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hello, world
|
||||
|
||||
|
||||
|
||||
=== TEST 2: read buffered body (timed out)
|
||||
--- config
|
||||
client_body_timeout 1ms;
|
||||
location = /test {
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.var.request_body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
--- raw_request eval
|
||||
"POST /test HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Content-Length: 100\r
|
||||
Connection: close\r
|
||||
|
||||
hello, world"
|
||||
--- response_body:
|
||||
--- error_code:
|
||||
|
||||
|
||||
|
||||
=== TEST 3: read buffered body and then subrequest
|
||||
--- config
|
||||
location /foo {
|
||||
echo -n foo;
|
||||
}
|
||||
location = /test {
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
local res = ngx.location.capture("/foo");
|
||||
ngx.say(ngx.var.request_body)
|
||||
ngx.say("sub: ", res.body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hello, world
|
||||
sub: foo
|
||||
|
||||
|
||||
|
||||
=== TEST 4: first subrequest and then read buffered body
|
||||
--- config
|
||||
location /foo {
|
||||
echo -n foo;
|
||||
}
|
||||
location = /test {
|
||||
rewrite_by_lua '
|
||||
local res = ngx.location.capture("/foo");
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.var.request_body)
|
||||
ngx.say("sub: ", res.body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hello, world
|
||||
sub: foo
|
||||
|
|
@ -669,3 +669,70 @@ GET /
|
|||
--- response_headers
|
||||
X-Foo: bar
|
||||
|
||||
|
||||
|
||||
=== TEST 35: rewrite last before rewrite_by_lua
|
||||
--- config
|
||||
location /main {
|
||||
rewrite ^/main/xyz\.html$ /abc.html last;
|
||||
rewrite_by_lua 'ngx.exit(503)';
|
||||
}
|
||||
location ~ /abc.html {
|
||||
echo abc;
|
||||
}
|
||||
--- request
|
||||
GET /main/xyz.html
|
||||
--- response_body
|
||||
abc
|
||||
|
||||
|
||||
|
||||
=== TEST 36: rewrite last before rewrite_by_lua_file
|
||||
--- config
|
||||
location /main {
|
||||
rewrite ^/main/xyz\.html$ /abc.html last;
|
||||
rewrite_by_lua_file html/exit.lua;
|
||||
}
|
||||
location ~ /abc.html {
|
||||
echo abc;
|
||||
}
|
||||
--- user_files
|
||||
>>> exit.lua
|
||||
ngx.exit(503)
|
||||
--- request
|
||||
GET /main/xyz.html
|
||||
--- response_body
|
||||
abc
|
||||
|
||||
|
||||
|
||||
=== TEST 37: rewrite before rewrite_by_lua
|
||||
--- config
|
||||
location /main {
|
||||
rewrite ^/main/xyz\.html$ /abc.html;
|
||||
rewrite_by_lua 'ngx.exit(503)';
|
||||
}
|
||||
location ~ /abc.html {
|
||||
echo abc;
|
||||
}
|
||||
--- request
|
||||
GET /main/xyz.html
|
||||
--- response_body
|
||||
abc
|
||||
|
||||
|
||||
|
||||
=== TEST 38: rewrite break before rewrite_by_lua
|
||||
--- config
|
||||
location /main {
|
||||
rewrite ^/main/xyz\.html$ /abc.html break;
|
||||
rewrite_by_lua 'ngx.exit(503)';
|
||||
}
|
||||
location ~ /abc.html {
|
||||
echo abc;
|
||||
}
|
||||
--- request
|
||||
GET /main/xyz.html
|
||||
--- response_body_like: 503 Service Temporarily Unavailable
|
||||
--- error_code: 503
|
||||
|
||||
|
|
|
@ -323,3 +323,31 @@ hello
|
|||
--- response_body
|
||||
hello
|
||||
|
||||
|
||||
|
||||
=== TEST 15: access_by_lua + ngx.exec + subrequest capture
|
||||
--- config
|
||||
location /main {
|
||||
access_by_lua '
|
||||
res = ngx.location.capture("/test_loc");
|
||||
ngx.print("hello, ", res.body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
location /test_loc {
|
||||
rewrite_by_lua '
|
||||
ngx.exec("@proxy")
|
||||
';
|
||||
}
|
||||
location @proxy {
|
||||
#echo proxy;
|
||||
proxy_pass http://127.0.0.1:$server_port/foo;
|
||||
}
|
||||
location /foo {
|
||||
echo bah;
|
||||
}
|
||||
--- request
|
||||
GET /main
|
||||
--- response_body
|
||||
hello, bah
|
||||
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
use lib 'lib';
|
||||
use Test::Nginx::Socket;
|
||||
|
||||
#worker_connections(1014);
|
||||
#master_process_enabled(1);
|
||||
#log_level('warn');
|
||||
|
||||
repeat_each(2);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 2);
|
||||
|
||||
#no_diff();
|
||||
#no_long_string();
|
||||
#master_on();
|
||||
#workers(2);
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: read buffered body
|
||||
--- config
|
||||
location = /test {
|
||||
access_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.var.request_body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hello, world
|
||||
|
||||
|
||||
|
||||
=== TEST 2: read buffered body (timed out)
|
||||
--- config
|
||||
client_body_timeout 1ms;
|
||||
location = /test {
|
||||
access_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.var.request_body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
--- raw_request eval
|
||||
"POST /test HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Content-Length: 100\r
|
||||
Connection: close\r
|
||||
|
||||
hello, world"
|
||||
--- response_body:
|
||||
--- error_code:
|
||||
|
||||
|
||||
|
||||
=== TEST 3: read buffered body and then subrequest
|
||||
--- config
|
||||
location /foo {
|
||||
echo -n foo;
|
||||
}
|
||||
location = /test {
|
||||
access_by_lua '
|
||||
ngx.req.read_body()
|
||||
local res = ngx.location.capture("/foo");
|
||||
ngx.say(ngx.var.request_body)
|
||||
ngx.say("sub: ", res.body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hello, world
|
||||
sub: foo
|
||||
|
||||
|
||||
|
||||
=== TEST 4: first subrequest and then read buffered body
|
||||
--- config
|
||||
location /foo {
|
||||
echo -n foo;
|
||||
}
|
||||
location = /test {
|
||||
access_by_lua '
|
||||
local res = ngx.location.capture("/foo");
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.var.request_body)
|
||||
ngx.say("sub: ", res.body)
|
||||
';
|
||||
content_by_lua return;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hello, world
|
||||
sub: foo
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
use lib 'lib';
|
||||
use Test::Nginx::Socket;
|
||||
|
||||
#worker_connections(1014);
|
||||
worker_connections(1014);
|
||||
#master_on();
|
||||
#workers(2);
|
||||
#log_level('warn');
|
||||
|
@ -12,8 +12,12 @@ repeat_each(2);
|
|||
|
||||
plan tests => repeat_each() * (blocks() * 2);
|
||||
|
||||
no_root_location();
|
||||
|
||||
$ENV{TEST_NGINX_CLIENT_PORT} ||= $ENV{TEST_NGINX} ||= server_port();
|
||||
|
||||
#no_diff();
|
||||
#no_long_string();
|
||||
no_long_string();
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
@ -341,3 +345,281 @@ a = 3
|
|||
b = 4
|
||||
done
|
||||
|
||||
|
||||
|
||||
=== TEST 12: rewrite uri and args
|
||||
--- config
|
||||
location /bar {
|
||||
echo $query_string;
|
||||
}
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
rewrite_by_lua '
|
||||
ngx.req.set_uri_args("hello")
|
||||
ngx.req.set_uri("/bar", true);
|
||||
';
|
||||
proxy_pass http://www.taobao.com:5678;
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
hello
|
||||
|
||||
|
||||
|
||||
=== TEST 13: rewrite args (not break cycle by default)
|
||||
--- config
|
||||
location /bar {
|
||||
echo "bar: $uri?$args";
|
||||
}
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
rewrite_by_lua '
|
||||
ngx.req.set_uri_args("hello")
|
||||
ngx.req.set_uri("/bar", true)
|
||||
';
|
||||
echo "foo: $uri?$args";
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
bar: /bar?hello
|
||||
|
||||
|
||||
|
||||
=== TEST 14: rewrite (not break cycle explicitly)
|
||||
--- config
|
||||
location /bar {
|
||||
echo "bar: $uri?$args";
|
||||
}
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
rewrite_by_lua '
|
||||
ngx.req.set_uri_args("hello")
|
||||
ngx.req.set_uri("/bar", true)
|
||||
';
|
||||
echo "foo: $uri?$args";
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
bar: /bar?hello
|
||||
|
||||
|
||||
|
||||
=== TEST 15: rewrite (break cycle explicitly)
|
||||
--- config
|
||||
location /bar {
|
||||
echo "bar: $uri?$args";
|
||||
}
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
rewrite_by_lua '
|
||||
ngx.req.set_uri("/bar")
|
||||
ngx.req.set_uri_args("hello")
|
||||
';
|
||||
echo "foo: $uri?$args";
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
foo: /bar?hello
|
||||
|
||||
|
||||
|
||||
=== TEST 16: rewrite uri (zero-length)
|
||||
--- config
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
rewrite_by_lua '
|
||||
local res, err = pcall(ngx.req.set_uri, "")
|
||||
ngx.say("err: ", err)
|
||||
';
|
||||
echo "foo: $uri?$args";
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
err: attempt to use zero-length uri
|
||||
foo: /foo?world
|
||||
|
||||
|
||||
|
||||
=== TEST 17: rewrite uri and args
|
||||
--- config
|
||||
location /bar {
|
||||
echo $server_protocol $query_string;
|
||||
}
|
||||
location /foo {
|
||||
#rewrite ^ /bar?hello? break;
|
||||
rewrite_by_lua '
|
||||
ngx.req.set_uri_args("hello")
|
||||
ngx.req.set_uri("/bar")
|
||||
';
|
||||
proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT;
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
HTTP/1.0 hello
|
||||
|
||||
|
||||
|
||||
=== TEST 18: rewrite uri and args (table args)
|
||||
--- config
|
||||
location /bar {
|
||||
echo $server_protocol $query_string;
|
||||
}
|
||||
location /foo {
|
||||
#rewrite ^ /bar?hello? break;
|
||||
rewrite_by_lua '
|
||||
ngx.req.set_uri("/bar")
|
||||
ngx.req.set_uri_args({["ca t"] = "%"})
|
||||
';
|
||||
proxy_pass http://127.0.0.1:$TEST_NGINX_CLIENT_PORT;
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
HTTP/1.0 ca%20t=%25
|
||||
|
||||
|
||||
|
||||
=== TEST 19: rewrite uri and args (never returns)
|
||||
--- config
|
||||
location /bar {
|
||||
echo $query_string;
|
||||
}
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
rewrite_by_lua '
|
||||
ngx.req.set_uri_args("hello")
|
||||
ngx.req.set_uri("/bar", true);
|
||||
ngx.exit(503)
|
||||
';
|
||||
proxy_pass http://www.taobao.com:5678;
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
hello
|
||||
|
||||
|
||||
|
||||
=== TEST 20: ngx.req.set_uri with jump not allowed in access phase
|
||||
--- config
|
||||
location /bar {
|
||||
echo $query_string;
|
||||
}
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
set $err '';
|
||||
access_by_lua '
|
||||
res, err = pcall(ngx.req.set_uri, "/bar", true);
|
||||
ngx.var.err = err
|
||||
';
|
||||
echo "err: $err";
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
err: attempt to call ngx.req.set_uri to do location jump in contexts other than rewrite_by_lua and rewrite_by_lua_file
|
||||
|
||||
|
||||
|
||||
=== TEST 21: ngx.req.set_uri without jump allowed in access phase
|
||||
--- config
|
||||
location /bar {
|
||||
echo $query_string;
|
||||
}
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
set $err '';
|
||||
access_by_lua '
|
||||
ngx.req.set_uri("/bar")
|
||||
';
|
||||
echo "uri: $uri";
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
uri: /bar
|
||||
|
||||
|
||||
|
||||
=== TEST 22: ngx.req.set_uri with jump not allowed in content phase
|
||||
--- config
|
||||
location /bar {
|
||||
echo $query_string;
|
||||
}
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
content_by_lua '
|
||||
res, err = pcall(ngx.req.set_uri, "/bar", true);
|
||||
ngx.say("err: ", err)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
err: attempt to call ngx.req.set_uri to do location jump in contexts other than rewrite_by_lua and rewrite_by_lua_file
|
||||
|
||||
|
||||
|
||||
=== TEST 23: ngx.req.set_uri without jump allowed in content phase
|
||||
--- config
|
||||
location /bar {
|
||||
echo $query_string;
|
||||
}
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
set $err '';
|
||||
content_by_lua '
|
||||
ngx.req.set_uri("/bar")
|
||||
ngx.say("uri: ", ngx.var.uri)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
uri: /bar
|
||||
|
||||
|
||||
|
||||
=== TEST 24: ngx.req.set_uri with jump not allowed in set_by_lua
|
||||
--- config
|
||||
location /bar {
|
||||
echo $query_string;
|
||||
}
|
||||
location /foo {
|
||||
#set $args 'hello';
|
||||
set_by_lua $err '
|
||||
res, err = pcall(ngx.req.set_uri, "/bar", true);
|
||||
return err
|
||||
';
|
||||
echo "err: $err";
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
err: attempt to call ngx.req.set_uri to do location jump in contexts other than rewrite_by_lua and rewrite_by_lua_file
|
||||
|
||||
|
||||
|
||||
=== TEST 25: ngx.req.set_uri without jump is allowed in set_by_lua
|
||||
--- config
|
||||
location /bar {
|
||||
echo $query_string;
|
||||
}
|
||||
location /foo {
|
||||
set_by_lua $dummy '
|
||||
ngx.req.set_uri("/bar")
|
||||
return ""
|
||||
';
|
||||
echo "uri: $uri";
|
||||
}
|
||||
--- request
|
||||
GET /foo?world
|
||||
--- response_body
|
||||
uri: /bar
|
||||
|
|
@ -12,7 +12,7 @@ repeat_each(2);
|
|||
plan tests => repeat_each() * (blocks() * 2);
|
||||
|
||||
#no_diff();
|
||||
#no_long_string();
|
||||
no_long_string();
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
@ -547,3 +547,48 @@ not matched!
|
|||
bar
|
||||
baz
|
||||
|
||||
|
||||
|
||||
=== TEST 27: escaping sequences
|
||||
--- config
|
||||
location /re {
|
||||
content_by_lua_file html/a.lua;
|
||||
}
|
||||
--- user_files
|
||||
>>> a.lua
|
||||
m = ngx.re.match("hello, 1234", "(\\\s+)")
|
||||
if m then
|
||||
ngx.say("[", m[0], "]")
|
||||
else
|
||||
ngx.say("not matched!")
|
||||
end
|
||||
--- request
|
||||
GET /re
|
||||
--- response_body
|
||||
[ ]
|
||||
|
||||
|
||||
|
||||
=== TEST 28: escaping sequences
|
||||
--- config
|
||||
location /re {
|
||||
access_by_lua_file html/a.lua;
|
||||
content_by_lua return;
|
||||
}
|
||||
--- user_files
|
||||
>>> a.lua
|
||||
local uri = "<impact>2</impact>"
|
||||
local regex = '(?:>[\\w\\s]*</?\\w{2,}>)';
|
||||
ngx.say("regex: ", regex)
|
||||
m = ngx.re.match(uri, regex, "oi")
|
||||
if m then
|
||||
ngx.say("[", m[0], "]")
|
||||
else
|
||||
ngx.say("not matched!")
|
||||
end
|
||||
--- request
|
||||
GET /re
|
||||
--- response_body
|
||||
regex: (?:>[\w\s]*</?\w{2,}>)
|
||||
[>2</impact>]
|
||||
|
||||
|
|
|
@ -0,0 +1,795 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
use lib 'lib';
|
||||
use Test::Nginx::Socket;
|
||||
|
||||
#worker_connections(1014);
|
||||
#master_process_enabled(1);
|
||||
#log_level('warn');
|
||||
|
||||
#repeat_each(2);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 2 + 24);
|
||||
|
||||
#no_diff();
|
||||
no_long_string();
|
||||
#master_on();
|
||||
#workers(2);
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: read buffered body
|
||||
--- config
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.var.request_body)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hello, world
|
||||
|
||||
|
||||
|
||||
=== TEST 2: read buffered body (timed out)
|
||||
--- config
|
||||
client_body_timeout 1ms;
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.var.request_body)
|
||||
';
|
||||
}
|
||||
--- raw_request eval
|
||||
"POST /test HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Content-Length: 100\r
|
||||
Connection: close\r
|
||||
|
||||
hello, world"
|
||||
--- response_body:
|
||||
--- error_code:
|
||||
|
||||
|
||||
|
||||
=== TEST 3: read buffered body and then subrequest
|
||||
--- config
|
||||
location /foo {
|
||||
echo -n foo;
|
||||
}
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
local res = ngx.location.capture("/foo");
|
||||
ngx.say(ngx.var.request_body)
|
||||
ngx.say("sub: ", res.body)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hello, world
|
||||
sub: foo
|
||||
|
||||
|
||||
|
||||
=== TEST 4: first subrequest and then read buffered body
|
||||
--- config
|
||||
location /foo {
|
||||
echo -n foo;
|
||||
}
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
local res = ngx.location.capture("/foo");
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.var.request_body)
|
||||
ngx.say("sub: ", res.body)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hello, world
|
||||
sub: foo
|
||||
|
||||
|
||||
|
||||
=== TEST 5: read_body not allowed in set_by_lua
|
||||
--- config
|
||||
location /foo {
|
||||
echo -n foo;
|
||||
}
|
||||
location = /test {
|
||||
set_by_lua $has_read_body '
|
||||
return ngx.req.read_body and "defined" or "undef"
|
||||
';
|
||||
echo "ngx.req.read_body: $has_read_body";
|
||||
}
|
||||
--- request
|
||||
GET /test
|
||||
--- response_body
|
||||
ngx.req.read_body: undef
|
||||
|
||||
|
||||
|
||||
=== TEST 6: read_body not allowed in set_by_lua
|
||||
--- config
|
||||
location /foo {
|
||||
echo -n foo;
|
||||
}
|
||||
location = /test {
|
||||
set $bool '';
|
||||
header_filter_by_lua '
|
||||
ngx.var.bool = (ngx.req.read_body and "defined" or "undef")
|
||||
';
|
||||
content_by_lua '
|
||||
ngx.send_headers()
|
||||
ngx.say("ngx.req.read_body: ", ngx.var.bool)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /test
|
||||
--- response_body
|
||||
ngx.req.read_body: undef
|
||||
|
||||
|
||||
|
||||
=== TEST 7: discard body
|
||||
--- config
|
||||
location = /foo {
|
||||
content_by_lua '
|
||||
ngx.req.discard_body()
|
||||
ngx.say("body: ", ngx.var.request_body)
|
||||
';
|
||||
}
|
||||
location = /bar {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say("body: ", ngx.var.request_body)
|
||||
';
|
||||
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["POST /foo
|
||||
hello, world",
|
||||
"POST /bar
|
||||
hiya, world"]
|
||||
--- response_body eval
|
||||
["body: nil\n",
|
||||
"body: hiya, world\n"]
|
||||
|
||||
|
||||
|
||||
=== TEST 8: not discard body
|
||||
--- config
|
||||
location = /foo {
|
||||
content_by_lua '
|
||||
-- ngx.req.discard_body()
|
||||
ngx.say("body: ", ngx.var.request_body)
|
||||
';
|
||||
}
|
||||
location = /bar {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say("body: ", ngx.var.request_body)
|
||||
';
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["POST /foo
|
||||
hello, world",
|
||||
"POST /bar
|
||||
hiya, world"]
|
||||
--- response_body eval
|
||||
["body: nil\n",
|
||||
qr/400 Bad Request/]
|
||||
--- error_code eval
|
||||
[200, '']
|
||||
|
||||
|
||||
|
||||
=== TEST 9: read buffered body and retrieve the data
|
||||
--- config
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.req.get_body_data())
|
||||
';
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hello, world
|
||||
|
||||
|
||||
|
||||
=== TEST 10: read buffered body to file and call get_body_data
|
||||
--- config
|
||||
client_body_in_file_only on;
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.req.get_body_data())
|
||||
';
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
nil
|
||||
|
||||
|
||||
|
||||
=== TEST 11: read buffered body to file and call get_body_file
|
||||
--- config
|
||||
client_body_in_file_only on;
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.req.get_body_file())
|
||||
';
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body_like: client_body_temp/
|
||||
|
||||
|
||||
|
||||
=== TEST 12: read buffered body to memory and retrieve the file
|
||||
--- config
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say(ngx.req.get_body_file())
|
||||
';
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
nil
|
||||
|
||||
|
||||
|
||||
=== TEST 13: read buffered body to memory and reset it with data in memory
|
||||
--- config
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.req.set_body_data("hiya, dear")
|
||||
ngx.say(ngx.req.get_body_data())
|
||||
ngx.say(ngx.var.request_body)
|
||||
ngx.say(ngx.var.echo_request_body)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
hiya, dear
|
||||
hiya, dear
|
||||
hiya, dear
|
||||
|
||||
|
||||
|
||||
=== TEST 14: read body to file and then override it with data in memory
|
||||
--- config
|
||||
client_body_in_file_only on;
|
||||
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.req.set_body_data("hello, baby")
|
||||
ngx.say(ngx.req.get_body_data())
|
||||
ngx.say(ngx.var.request_body)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
yeah
|
||||
--- response_body
|
||||
hello, baby
|
||||
hello, baby
|
||||
|
||||
|
||||
|
||||
=== TEST 15: do not read the current request body but replace it with our own in memory
|
||||
--- config
|
||||
client_body_in_file_only on;
|
||||
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.set_body_data("hello, baby")
|
||||
ngx.say(ngx.req.get_body_data())
|
||||
ngx.say(ngx.var.request_body)
|
||||
-- ngx.location.capture("/sleep")
|
||||
';
|
||||
}
|
||||
location = /sleep {
|
||||
echo_sleep 0.5;
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["POST /test\nyeah", "POST /test\nblah"]
|
||||
--- response_body eval
|
||||
["hello, baby
|
||||
hello, baby
|
||||
",
|
||||
"hello, baby
|
||||
hello, baby
|
||||
"]
|
||||
|
||||
|
||||
|
||||
=== TEST 16: read buffered body to file and reset it to a new file
|
||||
--- config
|
||||
client_body_in_file_only on;
|
||||
|
||||
location = /test {
|
||||
set $old '';
|
||||
set $new '';
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.var.old = ngx.req.get_body_file()
|
||||
ngx.req.set_body_file(ngx.var.realpath_root .. "/a.txt")
|
||||
ngx.var.new = ngx.req.get_body_file()
|
||||
';
|
||||
#echo_request_body;
|
||||
proxy_pass http://127.0.0.1:$server_port/echo;
|
||||
#proxy_pass http://127.0.0.1:7890/echo;
|
||||
add_header X-Old $old;
|
||||
add_header X-New $new;
|
||||
}
|
||||
location /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- user_files
|
||||
>>> a.txt
|
||||
Will you change this world?
|
||||
--- raw_response_headers_like
|
||||
X-Old: \S+/client_body_temp/\d+\r
|
||||
.*?X-New: \S+/html/a\.txt\r
|
||||
--- response_body
|
||||
Will you change this world?
|
||||
|
||||
|
||||
|
||||
=== TEST 17: read buffered body to file and reset it to a new file
|
||||
--- config
|
||||
client_body_in_file_only on;
|
||||
|
||||
location = /test {
|
||||
set $old '';
|
||||
set $new '';
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.var.old = ngx.req.get_body_file() or ""
|
||||
ngx.req.set_body_file(ngx.var.realpath_root .. "/a.txt")
|
||||
ngx.var.new = ngx.req.get_body_file()
|
||||
';
|
||||
#echo_request_body;
|
||||
proxy_pass http://127.0.0.1:$server_port/echo;
|
||||
#proxy_pass http://127.0.0.1:7890/echo;
|
||||
add_header X-Old $old;
|
||||
add_header X-New $new;
|
||||
}
|
||||
location /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world!
|
||||
--- user_files
|
||||
>>> a.txt
|
||||
Will you change this world?
|
||||
--- raw_response_headers_like
|
||||
X-Old: \S+/client_body_temp/\d+\r
|
||||
.*?X-New: \S+/html/a\.txt\r
|
||||
--- response_body
|
||||
Will you change this world?
|
||||
|
||||
|
||||
|
||||
=== TEST 18: read buffered body to file and reset it to a new file (auto-clean)
|
||||
--- config
|
||||
client_body_in_file_only on;
|
||||
|
||||
location = /test {
|
||||
set $old '';
|
||||
set $new '';
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.var.old = ngx.req.get_body_file()
|
||||
local a_file = ngx.var.realpath_root .. "/a.txt"
|
||||
ngx.req.set_body_file(a_file, true)
|
||||
local b_file = ngx.var.realpath_root .. "/b.txt"
|
||||
ngx.req.set_body_file(b_file, true)
|
||||
ngx.say("a.txt exists: ", io.open(a_file) and "yes" or "no")
|
||||
ngx.say("b.txt exists: ", io.open(b_file) and "yes" or "no")
|
||||
';
|
||||
}
|
||||
location /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- user_files
|
||||
>>> a.txt
|
||||
Will you change this world?
|
||||
>>> b.txt
|
||||
Sure I will!
|
||||
--- response_body
|
||||
a.txt exists: no
|
||||
b.txt exists: yes
|
||||
|
||||
|
||||
|
||||
=== TEST 19: read buffered body to memoary and reset it to a new file (auto-clean)
|
||||
--- config
|
||||
client_body_in_file_only off;
|
||||
|
||||
location = /test {
|
||||
set $old '';
|
||||
set $new '';
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
local a_file = ngx.var.realpath_root .. "/a.txt"
|
||||
ngx.req.set_body_file(a_file, true)
|
||||
';
|
||||
echo_request_body;
|
||||
}
|
||||
location /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["POST /test
|
||||
hello, world",
|
||||
"POST /test
|
||||
hey, you"]
|
||||
--- user_files
|
||||
>>> a.txt
|
||||
Will you change this world?
|
||||
--- response_body eval
|
||||
["Will you change this world?\n",
|
||||
qr/500 Internal Server Error/]
|
||||
--- error_code eval
|
||||
[200, 500]
|
||||
|
||||
|
||||
|
||||
=== TEST 20: read buffered body to memoary and reset it to a new file (no auto-clean)
|
||||
--- config
|
||||
client_body_in_file_only off;
|
||||
|
||||
location = /test {
|
||||
set $old '';
|
||||
set $new '';
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
local a_file = ngx.var.realpath_root .. "/a.txt"
|
||||
ngx.req.set_body_file(a_file, false)
|
||||
';
|
||||
echo_request_body;
|
||||
}
|
||||
location /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["POST /test
|
||||
hello, world",
|
||||
"POST /test
|
||||
hey, you"]
|
||||
--- user_files
|
||||
>>> a.txt
|
||||
Will you change this world?
|
||||
--- response_body eval
|
||||
["Will you change this world?\n",
|
||||
"Will you change this world?\n"]
|
||||
--- error_code eval
|
||||
[200, 200]
|
||||
|
||||
|
||||
|
||||
=== TEST 21: no request body and reset it to a new file (auto-clean)
|
||||
--- config
|
||||
client_body_in_file_only off;
|
||||
|
||||
location = /test {
|
||||
set $old '';
|
||||
set $new '';
|
||||
rewrite_by_lua '
|
||||
local a_file = ngx.var.realpath_root .. "/a.txt"
|
||||
ngx.req.set_body_file(a_file, false)
|
||||
';
|
||||
echo_request_body;
|
||||
}
|
||||
location /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["POST /test
|
||||
hello, world",
|
||||
"POST /test
|
||||
hey, you"]
|
||||
--- user_files
|
||||
>>> a.txt
|
||||
Will you change this world?
|
||||
--- response_body eval
|
||||
["Will you change this world?\n",
|
||||
"Will you change this world?\n"]
|
||||
--- error_code eval
|
||||
[200, 200]
|
||||
|
||||
|
||||
|
||||
=== TEST 22: no request body and reset it to a new file (no auto-clean)
|
||||
--- config
|
||||
client_body_in_file_only off;
|
||||
|
||||
location = /test {
|
||||
set $old '';
|
||||
set $new '';
|
||||
rewrite_by_lua '
|
||||
local a_file = ngx.var.realpath_root .. "/a.txt"
|
||||
ngx.req.set_body_file(a_file, true)
|
||||
';
|
||||
echo_request_body;
|
||||
}
|
||||
location /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["POST /test
|
||||
hello, world",
|
||||
"POST /test
|
||||
hey, you"]
|
||||
--- user_files
|
||||
>>> a.txt
|
||||
Will you change this world?
|
||||
--- response_body eval
|
||||
["Will you change this world?\n",
|
||||
qr/500 Internal Server Error/]
|
||||
--- error_code eval
|
||||
[200, 500]
|
||||
|
||||
|
||||
|
||||
=== TEST 23: read buffered body to memory and reset it with data in memory + proxy
|
||||
--- config
|
||||
location = /test {
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.req.set_body_data("hiya, dear dear friend!")
|
||||
';
|
||||
proxy_pass http://127.0.0.1:$server_port/echo;
|
||||
}
|
||||
location = /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body chomp
|
||||
hiya, dear dear friend!
|
||||
|
||||
|
||||
|
||||
=== TEST 24: discard request body and reset it to a new file (no auto-clean)
|
||||
--- config
|
||||
client_body_in_file_only off;
|
||||
|
||||
location = /test {
|
||||
set $old '';
|
||||
set $new '';
|
||||
rewrite_by_lua '
|
||||
ngx.req.discard_body()
|
||||
local a_file = ngx.var.realpath_root .. "/a.txt"
|
||||
ngx.req.set_body_file(a_file, true)
|
||||
';
|
||||
echo_request_body;
|
||||
}
|
||||
location /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["POST /test
|
||||
hello, world",
|
||||
"POST /test
|
||||
hey, you"]
|
||||
--- user_files
|
||||
>>> a.txt
|
||||
Will you change this world?
|
||||
--- response_body eval
|
||||
["Will you change this world?\n",
|
||||
qr/500 Internal Server Error/]
|
||||
--- error_code eval
|
||||
[200, 500]
|
||||
|
||||
|
||||
|
||||
=== TEST 25: discard body and then read
|
||||
--- config
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.req.discard_body()
|
||||
ngx.req.read_body()
|
||||
ngx.print(ngx.req.get_body_data())
|
||||
';
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["POST /test
|
||||
hello, world",
|
||||
"POST /test
|
||||
hello, world"]
|
||||
--- response_body eval
|
||||
["nil","nil"]
|
||||
|
||||
|
||||
|
||||
=== TEST 26: set empty request body in memory
|
||||
--- config
|
||||
location = /test {
|
||||
rewrite_by_lua '
|
||||
ngx.req.set_body_data("")
|
||||
';
|
||||
proxy_pass http://127.0.0.1:$server_port/echo;
|
||||
}
|
||||
location = /echo {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say("body: [", ngx.req.get_body_data(), "]")
|
||||
';
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["POST /test
|
||||
hello, world",
|
||||
"POST /test
|
||||
hello, world"]
|
||||
--- response_body eval
|
||||
["body: [nil]\n","body: [nil]\n"]
|
||||
|
||||
|
||||
|
||||
=== TEST 27: set empty request body in file
|
||||
--- config
|
||||
location = /test {
|
||||
rewrite_by_lua '
|
||||
ngx.req.set_body_file(ngx.var.realpath_root .. "/a.txt")
|
||||
';
|
||||
proxy_pass http://127.0.0.1:$server_port/echo;
|
||||
}
|
||||
location = /echo {
|
||||
content_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.say("body: [", ngx.req.get_body_data(), "]")
|
||||
';
|
||||
}
|
||||
--- user_files
|
||||
>>> a.txt
|
||||
--- pipelined_requests eval
|
||||
["POST /test
|
||||
hello, world",
|
||||
"POST /test
|
||||
hello, world"]
|
||||
--- response_body eval
|
||||
["body: [nil]\n","body: [nil]\n"]
|
||||
|
||||
|
||||
|
||||
=== TEST 28: read and set body
|
||||
--- config
|
||||
location /test {
|
||||
lua_need_request_body on;
|
||||
access_by_lua_file html/myscript.lua;
|
||||
echo_request_body;
|
||||
}
|
||||
--- user_files
|
||||
>>> myscript.lua
|
||||
local data, data2 = ngx.req.get_post_args(), {}
|
||||
for k, v in pairs(data) do
|
||||
if type(v) == "table" then
|
||||
for i, val in ipairs(v) do
|
||||
local s = ngx.escape_uri(string.upper(k)) .. '='
|
||||
.. ngx.escape_uri(string.upper(val))
|
||||
table.insert(data2, s)
|
||||
end
|
||||
else
|
||||
local s = ngx.escape_uri(string.upper(k)) .. '='
|
||||
.. ngx.escape_uri(string.upper(v))
|
||||
table.insert(data2, s)
|
||||
end
|
||||
end
|
||||
ngx.req.set_body_data(table.concat(data2, "&"))
|
||||
--- request
|
||||
POST /test
|
||||
a=1&a=2&b=hello&c=world
|
||||
--- response_body
|
||||
B=HELLO&A=1&A=2&C=WORLD
|
||||
--- SKIP
|
||||
|
||||
|
||||
|
||||
=== TEST 29: read buffered body to memory and reset it with data in memory + proxy twice
|
||||
--- config
|
||||
location = /test {
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.req.set_body_data("hiya, dear dear friend!")
|
||||
ngx.req.set_body_data("howdy, my dear little sister!")
|
||||
';
|
||||
proxy_pass http://127.0.0.1:$server_port/echo;
|
||||
}
|
||||
location = /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body chomp
|
||||
howdy, my dear little sister!
|
||||
|
||||
|
||||
|
||||
=== TEST 30: read buffered body to memory and reset it with data in memory and then reset it to file
|
||||
--- config
|
||||
location = /test {
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.req.set_body_data("hiya, dear dear friend!")
|
||||
ngx.req.set_body_file(ngx.var.realpath_root .. "/a.txt")
|
||||
';
|
||||
proxy_pass http://127.0.0.1:$server_port/echo;
|
||||
}
|
||||
location = /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- user_files
|
||||
>>> a.txt
|
||||
howdy, my dear little sister!
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body
|
||||
howdy, my dear little sister!
|
||||
|
||||
|
||||
|
||||
=== TEST 31: read buffered body to memory and reset it with empty string + proxy twice
|
||||
--- config
|
||||
location = /test {
|
||||
rewrite_by_lua '
|
||||
ngx.req.read_body()
|
||||
ngx.req.set_body_data("hiya, dear dear friend!")
|
||||
ngx.req.set_body_data("")
|
||||
';
|
||||
proxy_pass http://127.0.0.1:$server_port/echo;
|
||||
}
|
||||
location = /echo {
|
||||
echo_read_request_body;
|
||||
echo_request_body;
|
||||
}
|
||||
--- request
|
||||
POST /test
|
||||
hello, world
|
||||
--- response_body chomp
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
use lib 'lib';
|
||||
use Test::Nginx::Socket;
|
||||
|
||||
#worker_connections(1014);
|
||||
#master_process_enabled(1);
|
||||
#log_level('warn');
|
||||
|
||||
repeat_each(2);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 2);
|
||||
|
||||
#no_diff();
|
||||
no_long_string();
|
||||
#master_on();
|
||||
#workers(2);
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: set indexed variables to nil
|
||||
--- config
|
||||
location = /test {
|
||||
set $var 32;
|
||||
content_by_lua '
|
||||
ngx.say("old: ", ngx.var.var)
|
||||
ngx.var.var = nil
|
||||
ngx.say("new: ", ngx.var.var)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /test
|
||||
--- response_body
|
||||
old: 32
|
||||
new: nil
|
||||
|
||||
|
||||
|
||||
=== TEST 2: set variables with set_handler to nil
|
||||
--- config
|
||||
location = /test {
|
||||
content_by_lua '
|
||||
ngx.say("old: ", ngx.var.args)
|
||||
ngx.var.args = nil
|
||||
ngx.say("new: ", ngx.var.args)
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /test?hello=world
|
||||
--- response_body
|
||||
old: hello=world
|
||||
new: nil
|
||||
|
|
@ -22,7 +22,8 @@ if [[ "$BUILD_CLEAN" -eq 1 || ! -f Makefile || "$root/config" -nt Makefile || "$
|
|||
./configure --prefix=$root/work \
|
||||
--add-module=$root \
|
||||
--add-module=$root/deps/ngx_devel_kit \
|
||||
$opts
|
||||
$opts \
|
||||
--with-debug
|
||||
fi
|
||||
|
||||
if [ -f $root/work/sbin/nginx ]; then
|
||||
|
|
|
@ -35,6 +35,6 @@ ngx-build $force $version \
|
|||
--add-module=$root/../drizzle-nginx-module \
|
||||
--add-module=$home/work/nginx/ngx_http_upstream_keepalive-2ce9d8a1ca93 \
|
||||
--add-module=$root/../rds-json-nginx-module \
|
||||
$opts #\
|
||||
#--with-debug
|
||||
$opts \
|
||||
--with-debug
|
||||
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Addr4
|
||||
fun:lj_str_new
|
||||
fun:lua_setfield
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Addr4
|
||||
fun:lj_str_new
|
||||
fun:lua_getfield
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:ngx_alloc
|
||||
fun:(below main)
|
||||
}
|
||||
{
|
||||
<insert_a_suppression_name_here>
|
||||
Memcheck:Param
|
||||
|
|
Загрузка…
Ссылка в новой задаче