feature: implemented the ngx.req.raw_header() function for returning the original raw HTTP protocol header string received by Nginx. thanks Matthieu Tourne for requesting this.
This commit is contained in:
Родитель
4927e75b05
Коммит
c95456c872
34
README
34
README
|
@ -2154,6 +2154,40 @@ Nginx API for Lua
|
|||
|
||||
This method was first introduced in the "v0.7.17" release.
|
||||
|
||||
ngx.req.raw_header
|
||||
syntax: *str = ngx.req.raw_header(no_request_line?)*
|
||||
|
||||
context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*,
|
||||
header_filter_by_lua**
|
||||
|
||||
Returns the original raw HTTP protocol header received by the Nginx
|
||||
server.
|
||||
|
||||
By default, the request line and trailing "CR LF" terminator will also
|
||||
be included. For example,
|
||||
|
||||
ngx.print(ngx.req.raw_header())
|
||||
|
||||
gives something like this:
|
||||
|
||||
GET /t HTTP/1.1
|
||||
Host: localhost
|
||||
Connection: close
|
||||
Foo: bar
|
||||
|
||||
You can specify the optional "no_request_line" argument as a "true"
|
||||
value to exclude the request line from the result. For example,
|
||||
|
||||
ngx.print(ngx.req.raw_header(true))
|
||||
|
||||
outputs something like this:
|
||||
|
||||
Host: localhost
|
||||
Connection: close
|
||||
Foo: bar
|
||||
|
||||
This method was first introduced in the "v0.7.17" release.
|
||||
|
||||
ngx.req.get_method
|
||||
syntax: *method_name = ngx.req.get_method()*
|
||||
|
||||
|
|
|
@ -1969,6 +1969,48 @@ Returns the HTTP version number for the current request as a Lua number.
|
|||
|
||||
Current possible values are 1.0, 1.1, and 0.9. Returns `nil` for unrecognized values.
|
||||
|
||||
This method was first introduced in the `v0.7.17` release.
|
||||
|
||||
ngx.req.raw_header
|
||||
------------------
|
||||
**syntax:** *str = ngx.req.raw_header(no_request_line?)*
|
||||
|
||||
**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua**
|
||||
|
||||
Returns the original raw HTTP protocol header received by the Nginx server.
|
||||
|
||||
By default, the request line and trailing `CR LF` terminator will also be included. For example,
|
||||
|
||||
|
||||
ngx.print(ngx.req.raw_header())
|
||||
|
||||
|
||||
gives something like this:
|
||||
|
||||
|
||||
GET /t HTTP/1.1
|
||||
Host: localhost
|
||||
Connection: close
|
||||
Foo: bar
|
||||
|
||||
|
||||
|
||||
You can specify the optional
|
||||
`no_request_line` argument as a `true` value to exclude the request line from the result. For example,
|
||||
|
||||
|
||||
ngx.print(ngx.req.raw_header(true))
|
||||
|
||||
|
||||
outputs something like this:
|
||||
|
||||
|
||||
Host: localhost
|
||||
Connection: close
|
||||
Foo: bar
|
||||
|
||||
|
||||
|
||||
This method was first introduced in the `v0.7.17` release.
|
||||
|
||||
ngx.req.get_method
|
||||
|
|
|
@ -1910,6 +1910,47 @@ Current possible values are 1.0, 1.1, and 0.9. Returns <code>nil</code> for unre
|
|||
|
||||
This method was first introduced in the <code>v0.7.17</code> release.
|
||||
|
||||
== ngx.req.raw_header ==
|
||||
'''syntax:''' ''str = ngx.req.raw_header(no_request_line?)''
|
||||
|
||||
'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*''
|
||||
|
||||
Returns the original raw HTTP protocol header received by the Nginx server.
|
||||
|
||||
By default, the request line and trailing <code>CR LF</code> terminator will also be included. For example,
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.print(ngx.req.raw_header())
|
||||
</geshi>
|
||||
|
||||
gives something like this:
|
||||
|
||||
<geshi lang="text">
|
||||
GET /t HTTP/1.1
|
||||
Host: localhost
|
||||
Connection: close
|
||||
Foo: bar
|
||||
|
||||
</geshi>
|
||||
|
||||
You can specify the optional
|
||||
<code>no_request_line</code> argument as a <code>true</code> value to exclude the request line from the result. For example,
|
||||
|
||||
<geshi lang="lua">
|
||||
ngx.print(ngx.req.raw_header(true))
|
||||
</geshi>
|
||||
|
||||
outputs something like this:
|
||||
|
||||
<geshi lang="text">
|
||||
Host: localhost
|
||||
Connection: close
|
||||
Foo: bar
|
||||
|
||||
</geshi>
|
||||
|
||||
This method was first introduced in the <code>v0.7.17</code> release.
|
||||
|
||||
== ngx.req.get_method ==
|
||||
'''syntax:''' ''method_name = ngx.req.get_method()''
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
|
||||
static int ngx_http_lua_ngx_req_http_version(lua_State *L);
|
||||
static int ngx_http_lua_ngx_req_raw_header(lua_State *L);
|
||||
static int ngx_http_lua_ngx_req_header_set_helper(lua_State *L);
|
||||
static int ngx_http_lua_ngx_header_get(lua_State *L);
|
||||
static int ngx_http_lua_ngx_header_set(lua_State *L);
|
||||
|
@ -62,6 +63,172 @@ ngx_http_lua_ngx_req_http_version(lua_State *L)
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_raw_header(lua_State *L)
|
||||
{
|
||||
int n;
|
||||
u_char *data, *p, *last;
|
||||
unsigned no_req_line = 0, found;
|
||||
size_t size;
|
||||
ngx_buf_t *b, *first = NULL;
|
||||
ngx_int_t i;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_connection_t *hc;
|
||||
|
||||
n = lua_gettop(L);
|
||||
if (n > 0) {
|
||||
no_req_line = lua_toboolean(L, 1);
|
||||
}
|
||||
|
||||
dd("no req line: %d", (int) no_req_line);
|
||||
|
||||
lua_pushlightuserdata(L, &ngx_http_lua_request_key);
|
||||
lua_rawget(L, LUA_GLOBALSINDEX);
|
||||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
hc = r->http_connection;
|
||||
|
||||
if (hc->nbusy) {
|
||||
b = NULL; /* to suppress a gcc warning */
|
||||
size = 0;
|
||||
for (i = 0; i < hc->nbusy; i++) {
|
||||
b = hc->busy[i];
|
||||
|
||||
if (first == NULL) {
|
||||
if (r->request_line.data >= b->pos
|
||||
|| r->request_line.data + r->request_line.len + 2
|
||||
<= b->start)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
dd("found first at %d", (int) i);
|
||||
first = b;
|
||||
}
|
||||
|
||||
size += b->pos - b->start;
|
||||
|
||||
if (b == r->header_in) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (r != r->main) {
|
||||
b = r->main->header_in;
|
||||
|
||||
} else {
|
||||
b = r->header_in;
|
||||
}
|
||||
|
||||
if (b == NULL) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size = b->pos - r->request_line.data;
|
||||
}
|
||||
|
||||
data = lua_newuserdata(L, size);
|
||||
|
||||
if (hc->nbusy) {
|
||||
last = data;
|
||||
found = 0;
|
||||
for (i = 0; i < hc->nbusy; i++) {
|
||||
b = hc->busy[i];
|
||||
|
||||
if (!found) {
|
||||
if (b != first) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dd("found first");
|
||||
found = 1;
|
||||
}
|
||||
|
||||
p = last;
|
||||
|
||||
if (b == first) {
|
||||
dd("request line: %.*s", (int) r->request_line.len,
|
||||
r->request_line.data);
|
||||
|
||||
if (no_req_line) {
|
||||
last = ngx_copy(last,
|
||||
r->request_line.data + r->request_line.len
|
||||
+ 2,
|
||||
b->pos - r->request_line.data
|
||||
- r->request_line.len - 2);
|
||||
|
||||
} else {
|
||||
last = ngx_copy(last,
|
||||
r->request_line.data,
|
||||
b->pos - r->request_line.data);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
last = ngx_copy(last, b->start, b->pos - b->start);
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* skip truncated header entries (if any) */
|
||||
while (last > p && last[-1] != LF) {
|
||||
last--;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (; p != last; p++) {
|
||||
if (*p == '\0') {
|
||||
if (p + 1 == last) {
|
||||
/* XXX this should not happen */
|
||||
dd("found string end!!");
|
||||
|
||||
} else if (*(p + 1) == LF) {
|
||||
*p = CR;
|
||||
|
||||
} else {
|
||||
*p = ':';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (b == r->header_in) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (no_req_line) {
|
||||
last = ngx_copy(data,
|
||||
r->request_line.data + r->request_line.len + 2,
|
||||
size - r->request_line.len - 2);
|
||||
|
||||
} else {
|
||||
last = ngx_copy(data, r->request_line.data, size);
|
||||
}
|
||||
|
||||
for (p = data; p != last; p++) {
|
||||
if (*p == '\0') {
|
||||
if (p + 1 != last && *(p + 1) == LF) {
|
||||
*p = CR;
|
||||
|
||||
} else {
|
||||
*p = ':';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushlstring(L, (char *) data, last - data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_get_headers(lua_State *L) {
|
||||
ngx_list_part_t *part;
|
||||
|
@ -506,6 +673,9 @@ ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L)
|
|||
lua_pushcfunction(L, ngx_http_lua_ngx_req_http_version);
|
||||
lua_setfield(L, -2, "http_version");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_raw_header);
|
||||
lua_setfield(L, -2, "raw_header");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_header_clear);
|
||||
lua_setfield(L, -2, "clear_header");
|
||||
|
||||
|
|
|
@ -2005,7 +2005,7 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L)
|
|||
{
|
||||
/* ngx.req table */
|
||||
|
||||
lua_createtable(L, 0 /* narr */, 22 /* nrec */); /* .req */
|
||||
lua_createtable(L, 0 /* narr */, 23 /* nrec */); /* .req */
|
||||
|
||||
ngx_http_lua_inject_req_header_api(log, L);
|
||||
ngx_http_lua_inject_req_uri_api(log, L);
|
||||
|
|
|
@ -124,7 +124,7 @@ n = 1
|
|||
--- request
|
||||
GET /test
|
||||
--- response_body
|
||||
n = 22
|
||||
n = 23
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
@ -146,7 +146,7 @@ n = 22
|
|||
--- request
|
||||
GET /test
|
||||
--- response_body
|
||||
n = 22
|
||||
n = 23
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
@ -173,7 +173,7 @@ n = 22
|
|||
--- request
|
||||
GET /test
|
||||
--- response_body
|
||||
n = 22
|
||||
n = 23
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
|
|
@ -0,0 +1,359 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
use lib 'lib';
|
||||
use Test::Nginx::Socket;
|
||||
|
||||
#worker_connections(1014);
|
||||
#master_on();
|
||||
#workers(2);
|
||||
#log_level('warn');
|
||||
|
||||
repeat_each(2);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 3 + 6);
|
||||
|
||||
#no_diff();
|
||||
no_long_string();
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: small header
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header())
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- response_body eval
|
||||
qq{GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: Close\r
|
||||
\r
|
||||
}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 2: large header
|
||||
--- config
|
||||
client_header_buffer_size 10;
|
||||
large_client_header_buffers 30 561;
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header())
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- more_headers eval
|
||||
CORE::join "\n", map { "Header$_: value-$_" } 1..512
|
||||
|
||||
--- response_body eval
|
||||
qq{GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: Close\r
|
||||
}
|
||||
.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"
|
||||
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 3: large header (no request line)
|
||||
--- config
|
||||
client_header_buffer_size 10;
|
||||
large_client_header_buffers 30 561;
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header(true))
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- more_headers eval
|
||||
CORE::join "\n", map { "Header$_: value-$_" } 1..512
|
||||
|
||||
--- response_body eval
|
||||
qq{Host: localhost\r
|
||||
Connection: Close\r
|
||||
}
|
||||
.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"
|
||||
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 4: small header (no request line)
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header(true))
|
||||
';
|
||||
}
|
||||
--- request
|
||||
GET /t
|
||||
--- response_body eval
|
||||
qq{Host: localhost\r
|
||||
Connection: Close\r
|
||||
\r
|
||||
}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 5: small header (no request line, with leading CRLF)
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header(true))
|
||||
';
|
||||
}
|
||||
--- raw_request eval
|
||||
"\r\nGET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
\r
|
||||
"
|
||||
--- response_body eval
|
||||
qq{Host: localhost\r
|
||||
Connection: close\r
|
||||
\r
|
||||
}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 6: small header, with leading CRLF
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header())
|
||||
';
|
||||
}
|
||||
--- raw_request eval
|
||||
"\r\nGET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
\r
|
||||
"
|
||||
--- response_body eval
|
||||
qq{GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
\r
|
||||
}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 7: large header, with leading CRLF
|
||||
--- config
|
||||
client_header_buffer_size 10;
|
||||
large_client_header_buffers 30 561;
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header())
|
||||
';
|
||||
}
|
||||
|
||||
--- raw_request eval
|
||||
"\r\nGET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
".
|
||||
(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"
|
||||
|
||||
--- response_body eval
|
||||
qq{GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
}
|
||||
.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"
|
||||
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 8: large header, with leading CRLF, excluding request line
|
||||
--- config
|
||||
client_header_buffer_size 10;
|
||||
large_client_header_buffers 30 561;
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header(true))
|
||||
';
|
||||
}
|
||||
|
||||
--- raw_request eval
|
||||
"\r\nGET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
".
|
||||
(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"
|
||||
|
||||
--- response_body eval
|
||||
qq{Host: localhost\r
|
||||
Connection: close\r
|
||||
}
|
||||
.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"
|
||||
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 9: large header, with lots of leading CRLF, excluding request line
|
||||
--- config
|
||||
client_header_buffer_size 10;
|
||||
large_client_header_buffers 30 561;
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header(true))
|
||||
';
|
||||
}
|
||||
|
||||
--- raw_request eval
|
||||
("\r\n" x 534) . "GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
".
|
||||
(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"
|
||||
|
||||
--- response_body eval
|
||||
qq{Host: localhost\r
|
||||
Connection: close\r
|
||||
}
|
||||
.(CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n"
|
||||
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 10: small header, pipelined
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header())
|
||||
';
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["GET /t", "GET /th"]
|
||||
|
||||
--- more_headers
|
||||
Foo: bar
|
||||
|
||||
--- response_body eval
|
||||
[qq{GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: keep-alive\r
|
||||
Foo: bar\r
|
||||
\r
|
||||
}, qq{GET /th HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
Foo: bar\r
|
||||
\r
|
||||
}]
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 11: large header, pipelined
|
||||
--- config
|
||||
client_header_buffer_size 10;
|
||||
large_client_header_buffers 30 561;
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header())
|
||||
';
|
||||
}
|
||||
--- pipelined_requests eval
|
||||
["GET /t", "GET /t"]
|
||||
|
||||
--- more_headers eval
|
||||
CORE::join "\n", map { "Header$_: value-$_" } 1..512
|
||||
|
||||
--- response_body eval
|
||||
my $headers = (CORE::join "\r\n", map { "Header$_: value-$_" } 1..512) . "\r\n\r\n";
|
||||
|
||||
[qq{GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: keep-alive\r
|
||||
$headers},
|
||||
qq{GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
$headers}]
|
||||
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 12: small header, multi-line header
|
||||
--- config
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header())
|
||||
';
|
||||
}
|
||||
--- raw_request eval
|
||||
"GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
Foo: bar baz\r
|
||||
blah
|
||||
\r
|
||||
"
|
||||
--- response_body eval
|
||||
qq{GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
Foo: bar baz\r
|
||||
blah
|
||||
\r
|
||||
}
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 13: large header, multi-line header
|
||||
--- config
|
||||
client_header_buffer_size 10;
|
||||
large_client_header_buffers 50 567;
|
||||
location /t {
|
||||
content_by_lua '
|
||||
ngx.print(ngx.req.raw_header())
|
||||
';
|
||||
}
|
||||
|
||||
--- raw_request eval
|
||||
my $headers = (CORE::join "\r\n", map { "Header$_: value-$_\r\n hello $_ world blah blah" } 1..512) . "\r\n\r\n";
|
||||
|
||||
qq{GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
$headers}
|
||||
|
||||
--- response_body eval
|
||||
qq{GET /t HTTP/1.1\r
|
||||
Host: localhost\r
|
||||
Connection: close\r
|
||||
}
|
||||
.(CORE::join "\r\n", map { "Header$_: value-$_\r\n hello $_ world blah blah" } 1..512) . "\r\n\r\n"
|
||||
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
Загрузка…
Ссылка в новой задаче