| #!/usr/bin/perl | |
| # (C) Maxim Dounin | |
| # Tests for embedded perl module. | |
| ############################################################################### | |
| use warnings; | |
| use strict; | |
| use Test::More; | |
| use Socket qw/ CRLF /; | |
| BEGIN { use FindBin; chdir($FindBin::Bin); } | |
| use lib 'lib'; | |
| use Test::Nginx; | |
| ############################################################################### | |
| select STDERR; $| = 1; | |
| select STDOUT; $| = 1; | |
| my $t = Test::Nginx->new()->has(qw/http perl rewrite/)->plan(17) | |
| ->write_file_expand('nginx.conf', <<'EOF'); | |
| %%TEST_GLOBALS%% | |
| daemon off; | |
| events { | |
| } | |
| http { | |
| %%TEST_GLOBALS_HTTP%% | |
| server { | |
| listen 127.0.0.1:8080; | |
| server_name localhost; | |
| location / { | |
| set $testvar "TEST"; | |
| perl 'sub { | |
| use warnings; | |
| use strict; | |
| my $r = shift; | |
| $r->send_http_header("text/plain"); | |
| return OK if $r->header_only; | |
| my $v = $r->variable("testvar"); | |
| $r->print("testvar: $v\n"); | |
| $r->print("host: ", $r->header_in("Host"), "\n"); | |
| $r->print("xfoo: ", $r->header_in("X-Foo"), "\n"); | |
| $r->print("cookie: ", $r->header_in("Cookie"), "\n"); | |
| $r->print("xff: ", $r->header_in("X-Forwarded-For"), "\n"); | |
| return OK; | |
| }'; | |
| } | |
| location /range { | |
| perl 'sub { | |
| use warnings; | |
| use strict; | |
| my $r = shift; | |
| $r->header_out("Content-Length", "42"); | |
| $r->allow_ranges(); | |
| $r->send_http_header("text/plain"); | |
| return OK if $r->header_only; | |
| $r->print("x" x 42); | |
| return OK; | |
| }'; | |
| } | |
| location /body { | |
| perl 'sub { | |
| use warnings; | |
| use strict; | |
| my $r = shift; | |
| if ($r->has_request_body(\&post)) { | |
| return OK; | |
| } | |
| return HTTP_BAD_REQUEST; | |
| sub post { | |
| my $r = shift; | |
| $r->send_http_header; | |
| $r->print("body: ", $r->request_body, "\n"); | |
| $r->print("file: ", $r->request_body_file, "\n"); | |
| } | |
| }'; | |
| } | |
| } | |
| } | |
| EOF | |
| $t->run(); | |
| ############################################################################### | |
| like(http_get('/'), qr/TEST/, 'perl response'); | |
| # various $r->header_in() cases | |
| like(http( | |
| 'GET / HTTP/1.0' . CRLF | |
| . 'Host: localhost' . CRLF . CRLF | |
| ), qr/host: localhost/, 'perl header_in known'); | |
| like(http( | |
| 'GET / HTTP/1.0' . CRLF | |
| . 'X-Foo: foo' . CRLF | |
| . 'Host: localhost' . CRLF . CRLF | |
| ), qr/xfoo: foo/, 'perl header_in unknown'); | |
| like(http( | |
| 'GET / HTTP/1.0' . CRLF | |
| . 'Cookie: foo' . CRLF | |
| . 'Host: localhost' . CRLF . CRLF | |
| ), qr/cookie: foo/, 'perl header_in cookie'); | |
| like(http( | |
| 'GET / HTTP/1.0' . CRLF | |
| . 'Cookie: foo1' . CRLF | |
| . 'Cookie: foo2' . CRLF | |
| . 'Host: localhost' . CRLF . CRLF | |
| ), qr/cookie: foo1; foo2/, 'perl header_in cookie2'); | |
| like(http( | |
| 'GET / HTTP/1.0' . CRLF | |
| . 'X-Forwarded-For: foo' . CRLF | |
| . 'Host: localhost' . CRLF . CRLF | |
| ), qr/xff: foo/, 'perl header_in xff'); | |
| like(http( | |
| 'GET / HTTP/1.0' . CRLF | |
| . 'X-Forwarded-For: foo1' . CRLF | |
| . 'X-Forwarded-For: foo2' . CRLF | |
| . 'Host: localhost' . CRLF . CRLF | |
| ), qr/xff: foo1, foo2/, 'perl header_in xff2'); | |
| # headers_out content-length tests with range filter | |
| like(http_get('/range'), qr/Content-Length: 42.*^x{42}$/ms, | |
| 'perl header_out content-length'); | |
| like(http( | |
| 'GET /range HTTP/1.0' . CRLF | |
| . 'Host: localhost' . CRLF | |
| . 'Range: bytes=0-1' . CRLF . CRLF | |
| ), qr/Content-Length: 2.*^xx$/ms, 'perl header_out content-length range'); | |
| like(http( | |
| 'GET /range HTTP/1.0' . CRLF | |
| . 'Host: localhost' . CRLF | |
| . 'Range: bytes=0-1,3-5' . CRLF . CRLF | |
| ), qr/Content-Length: (?!42).*^xx\x0d.*^xxx\x0d/ms, | |
| 'perl header_out content-length multipart'); | |
| TODO: { | |
| local $TODO = 'not yet'; | |
| like(http( | |
| 'GET /range HTTP/1.0' . CRLF | |
| . 'Host: localhost' . CRLF | |
| . 'Range: bytes=100000-' . CRLF . CRLF | |
| ), qr|^\QHTTP/1.1 416\E.*(?!xxx)|ms, 'perl range not satisfiable'); | |
| } | |
| # various request body tests | |
| like(http( | |
| 'GET /body HTTP/1.0' . CRLF | |
| . 'Host: localhost' . CRLF | |
| . 'Content-Length: 10' . CRLF . CRLF | |
| . '1234567890' | |
| ), qr/body: 1234567890/, 'perl body preread'); | |
| like(http( | |
| 'GET /body HTTP/1.0' . CRLF | |
| . 'Host: localhost' . CRLF | |
| . 'Content-Length: 10' . CRLF . CRLF, | |
| sleep => 0.1, | |
| body => '1234567890' | |
| ), qr/body: 1234567890/, 'perl body late'); | |
| like(http( | |
| 'GET /body HTTP/1.0' . CRLF | |
| . 'Host: localhost' . CRLF | |
| . 'Content-Length: 10' . CRLF . CRLF | |
| . '12345', | |
| sleep => 0.1, | |
| body => '67890' | |
| ), qr/body: 1234567890/, 'perl body split'); | |
| like(http( | |
| 'GET /body HTTP/1.1' . CRLF | |
| . 'Host: localhost' . CRLF | |
| . 'Connection: close' . CRLF | |
| . 'Transfer-Encoding: chunked' . CRLF . CRLF | |
| . 'a' . CRLF | |
| . '1234567890' . CRLF | |
| . '0' . CRLF . CRLF | |
| ), qr/body: 1234567890/, 'perl body chunked'); | |
| like(http( | |
| 'GET /body HTTP/1.1' . CRLF | |
| . 'Host: localhost' . CRLF | |
| . 'Connection: close' . CRLF | |
| . 'Transfer-Encoding: chunked' . CRLF . CRLF, | |
| sleep => 0.1, | |
| body => 'a' . CRLF . '1234567890' . CRLF . '0' . CRLF . CRLF | |
| ), qr/body: 1234567890/, 'perl body chunked late'); | |
| like(http( | |
| 'GET /body HTTP/1.1' . CRLF | |
| . 'Host: localhost' . CRLF | |
| . 'Connection: close' . CRLF | |
| . 'Transfer-Encoding: chunked' . CRLF . CRLF | |
| . 'a' . CRLF | |
| . '12345', | |
| sleep => 0.1, | |
| body => '67890' . CRLF . '0' . CRLF . CRLF | |
| ), qr/body: 1234567890/, 'perl body chunked split'); | |
| ############################################################################### |