resolved conflicts while merging the "master" branch to "shm".

This commit is contained in:
agentzh (章亦春) 2011-10-24 12:34:37 +08:00
Родитель 4c71768761 5973268d3a
Коммит b71a0b52a6
42 изменённых файлов: 4782 добавлений и 617 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -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

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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
Просмотреть файл

@ -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);

675
src/ngx_http_lua_req_body.c Normal file
Просмотреть файл

@ -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,

93
src/ngx_http_lua_uri.c Normal file
Просмотреть файл

@ -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;
}

12
src/ngx_http_lua_uri.h Normal file
Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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 '

Просмотреть файл

@ -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

103
t/023-rewrite/req-body.t Normal file
Просмотреть файл

@ -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

103
t/024-access/req-body.t Normal file
Просмотреть файл

@ -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>]

795
t/044-req-body.t Normal file
Просмотреть файл

@ -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

53
t/045-ngx-var.t Normal file
Просмотреть файл

@ -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