blob: 0522c503e5f9e6828ea3495414484b3848df0e3c [file] [log] [blame]
#!/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(24)
->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->status(204) if $r->args =~ /204/;
$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");
}
}';
}
location /discard {
perl 'sub {
use warnings;
use strict;
my $r = shift;
$r->discard_request_body;
$r->send_http_header("text/plain");
return OK if $r->header_only;
$r->print("host: ", $r->header_in("Host"), "\n");
return OK;
}';
}
}
}
EOF
$t->run();
###############################################################################
like(http_get('/'), qr/ 200 .*TEST/s, 'perl response');
like(http_head('/'), qr/ 200 (?!.*TEST)/s, 'perl header_only');
like(http_get('/?204'), qr/ 204 (?!.*TEST)/s, 'perl status, args');
# 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' unless $t->has_version('1.17.2');
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');
}
TODO: {
todo_skip 'leaves coredump', 1 unless $t->has_version('1.17.1')
or $ENV{TEST_NGINX_UNSAFE};
like(http(
'GET / HTTP/1.0' . CRLF
. 'Host: localhost' . CRLF
. 'If-Match: tt' . CRLF . CRLF
), qr|200 OK|ms, 'perl precondition failed');
}
# various request body tests
like(http_get('/body'), qr/400 Bad Request/, 'perl no body');
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');
like(http(
'GET /discard HTTP/1.1' . CRLF
. 'Host: localhost' . CRLF
. 'Connection: close' . CRLF
. 'Transfer-Encoding: chunked' . CRLF . CRLF
. 'a' . CRLF
. '1234567890' . CRLF
. '0' . CRLF . CRLF
), qr/host: localhost/, 'perl body discard');
TODO: {
local $TODO = 'not yet' unless $t->has_version('1.17.2');
like(http(
'GET /discard HTTP/1.1' . CRLF
. 'Host: localhost' . CRLF
. 'Connection: close' . CRLF
. 'Transfer-Encoding: chunked' . CRLF . CRLF
. 'ak' . CRLF
. '1234567890' . CRLF
. '0' . CRLF . CRLF
), qr/400 Bad Request/, 'perl body discard bad chunk');
like(http(
'GET /body HTTP/1.1' . CRLF
. 'Host: localhost' . CRLF
. 'Connection: close' . CRLF
. 'Transfer-Encoding: chunked' . CRLF . CRLF
. 'ak' . CRLF
. '1234567890' . CRLF
. '0' . CRLF . CRLF
), qr/400 Bad Request/, 'perl body bad chunk');
}
###############################################################################