implemented, tested, and documented the new ngx.redirect(uri, status) method for Lua.

This commit is contained in:
agentzh (章亦春) 2010-11-20 19:26:36 +08:00
Родитель d98a147780
Коммит 32c3686a15
8 изменённых файлов: 249 добавлений и 10 удалений

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

@ -424,7 +424,43 @@ Named locations are also supported, but query strings are ignored. For example
...
}
This function never returns.
Note that this is very different from ngx.redirect() in that
it's just an internal redirect and no new HTTP traffic is involved.
This method never returns.
This method MUST be called before `ngx.send_headers()` or explicit response body
outputs by either `ngx.print` or `ngx.say`.
This method is very much like the `echo_exec`
directive in the ngx_echo module.
ngx.redirect(uri, status?)
--------------------------
Issue an HTTP 301 or 302 redirection to `uri`.
The optional `status` parameter specify whether
301 or 302 to be used. It's 302 (ngx.HTTP_MOVED_TEMPORARILY) by default.
This method MUST be called before `ngx.send_headers()` or explicit response body
outputs by either `ngx.print` or `ngx.say`.
Here's a small example:
return ngx.redirect("/foo")
which is equivalent to
return ngx.redirect("http://<host>:<port>/foo", ngx.HTTP_MOVED_TEMPORARILY)
where <host> is the current virtual server name and
<port> is the listerning port.
This method never returns.
This method is very much like the `rewrite` directive with the `redirect` modifier in the standard
`ngx_rewrite` module.
ngx.send_headers()
------------------

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

@ -2060,3 +2060,79 @@ ngx_http_lua_ngx_cookie_time(lua_State *L)
return 1;
}
int
ngx_http_lua_ngx_redirect(lua_State *L)
{
ngx_http_lua_ctx_t *ctx;
ngx_int_t rc;
int n;
u_char *p;
u_char *uri;
size_t len;
ngx_http_request_t *r;
n = lua_gettop(L);
if (n != 1 && n != 2) {
return luaL_error(L, "expecting one or two arguments");
}
p = (u_char *) luaL_checklstring(L, 1, &len);
if (n == 2) {
rc = (ngx_int_t) luaL_checknumber(L, 2);
if (rc != NGX_HTTP_MOVED_TEMPORARILY &&
rc != NGX_HTTP_MOVED_PERMANENTLY)
{
return luaL_error(L, "only ngx.HTTP_MOVED_TEMPORARILY and "
"ngx.HTTP_MOVED_PERMANENTLY are allowed");
}
} else {
rc = NGX_HTTP_MOVED_TEMPORARILY;
}
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");
}
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
if (ctx == NULL) {
return luaL_error(L, "no request ctx found");
}
if (ctx->headers_sent) {
return luaL_error(L, "attempt to call ngx.redirect after sending out the headers");
}
uri = ngx_palloc(r->pool, len);
if (uri == NULL) {
return luaL_error(L, "out of memory");
}
ngx_memcpy(uri, p, len);
r->headers_out.location = ngx_list_push(&r->headers_out.headers);
if (r->headers_out.location == NULL) {
return luaL_error(L, "out of memory");
}
r->headers_out.location->hash = 1;
r->headers_out.location->value.len = len;
r->headers_out.location->value.data = uri;
ngx_str_set(&r->headers_out.location->key, "Location");
r->headers_out.status = rc;
ctx->exit_code = rc;
ctx->exited = 1;
lua_pushnil(L);
return lua_error(L);
}

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

@ -41,6 +41,7 @@ int ngx_http_lua_ngx_strtime(lua_State *L);
int ngx_http_lua_ngx_utc_time(lua_State *L);
int ngx_http_lua_ngx_utc_strtime(lua_State *L);
int ngx_http_lua_ngx_cookie_time(lua_State *L);
int ngx_http_lua_ngx_redirect(lua_State *L);
int ngx_http_lua_ngx_location_capture(lua_State *L);

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

@ -530,6 +530,9 @@ init_ngx_lua_globals(lua_State *L)
lua_pushcfunction(L, ngx_http_lua_ngx_cookie_time);
lua_setfield(L, -2, "cookie_time");
lua_pushcfunction(L, ngx_http_lua_ngx_redirect);
lua_setfield(L, -2, "redirect");
lua_createtable(L, 0, 2); /* .location */
lua_pushcfunction(L, ngx_http_lua_ngx_location_capture);
lua_setfield(L, -2, "capture");

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

@ -201,8 +201,8 @@ Logged in 56
set $key "conv-uid-$arg_uid";
srcache_fetch GET /memc key=$key;
srcache_store PUT /memc key=$key;
#srcache_fetch GET /memc key=$key;
#srcache_store PUT /memc key=$key;
default_type 'application/json';
@ -281,8 +281,8 @@ Logged in 56
set $key "conv-uid-$arg_uid";
srcache_fetch GET /memc key=$key;
srcache_store PUT /memc key=$key;
#srcache_fetch GET /memc key=$key;
#srcache_store PUT /memc key=$key;
default_type 'application/json';
@ -358,8 +358,8 @@ Logged in 56
set $key "conv-uri-$query_string";
srcache_fetch GET /memc key=$key;
srcache_store PUT /memc key=$key;
#srcache_fetch GET /memc key=$key;
#srcache_store PUT /memc key=$key;
default_type 'application/json';

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

@ -7,8 +7,8 @@ use Test::Nginx::Socket;
#master_process_enabled(1);
#log_level('warn');
#repeat_each(120);
repeat_each(1);
repeat_each(2);
#repeat_each(1);
plan tests => blocks() * repeat_each() * 3;

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

@ -355,7 +355,8 @@ PUT: 201
cached: hello
=== TEST 12: POST (with body, memc method)
=== TEST 13: POST (with body, memc method)
--- config
location /flush {
set $memc_cmd flush_all;

122
t/022-redirect.t Normal file
Просмотреть файл

@ -0,0 +1,122 @@
# 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);
#repeat_each(1);
plan tests => blocks() * repeat_each() * 3;
#no_diff();
#no_long_string();
$ENV{TEST_NGINX_PORT} ||= 1984;
run_tests();
__DATA__
=== TEST 1: default 302
--- config
location /read {
content_by_lua '
ngx.redirect("http://www.taobao.com/foo");
ngx.say("hi")
';
}
--- request
GET /read
--- response_headers
Location: http://www.taobao.com/foo
--- response_body_like: 302 Found
--- error_code: 302
=== TEST 2: explicit 302
--- config
location /read {
content_by_lua '
ngx.redirect("http://www.taobao.com/foo", ngx.HTTP_MOVED_TEMPORARILY);
ngx.say("hi")
';
}
--- request
GET /read
--- response_headers
Location: http://www.taobao.com/foo
--- response_body_like: 302 Found
--- error_code: 302
=== TEST 3: explicit 301
--- config
location /read {
content_by_lua '
ngx.redirect("http://www.taobao.com/foo", ngx.HTTP_MOVED_PERMANENTLY);
ngx.say("hi")
';
}
--- request
GET /read
--- response_headers
Location: http://www.taobao.com/foo
--- response_body_like: 301 Moved Permanently
--- error_code: 301
=== TEST 4: bad rc
--- config
location /read {
content_by_lua '
ngx.redirect("http://www.taobao.com/foo", 404);
ngx.say("hi")
';
}
--- request
GET /read
--- response_headers
!Location
--- response_body_like: 500 Internal Server Error
--- error_code: 500
=== TEST 5: no args
--- config
location /read {
content_by_lua '
ngx.redirect()
ngx.say("hi")
';
}
--- request
GET /read
--- response_headers
!Location
--- response_body_like: 500 Internal Server Error
--- error_code: 500
=== TEST 6: relative uri
--- config
location /read {
content_by_lua '
ngx.redirect("/foo")
ngx.say("hi")
';
}
--- request
GET /read
--- raw_response_headers_like: Location: http://localhost(?::\d+)?/foo\r\n
--- response_body_like: 302 Found
--- error_code: 302