blob: 273230c695b336af16d10c15210872cff2ffbbf0 [file] [log] [blame]
#!/usr/bin/perl
# (C) Sergey Kandaurov
# (C) Nginx, Inc.
# Tests for image filter 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;
eval { require GD; };
plan(skip_all => 'GD not installed') if $@;
my $t = Test::Nginx->new()->has(qw/http proxy map image_filter/)->plan(39)
->write_file_expand('nginx.conf', <<'EOF');
%%TEST_GLOBALS%%
daemon off;
events {
}
http {
%%TEST_GLOBALS_HTTP%%
map $arg_w $w {
"" '-';
default $arg_w;
}
map $arg_h $h {
"" '-';
default $arg_h;
}
server {
listen 127.0.0.1:8080;
server_name localhost;
location /size {
image_filter size;
alias %%TESTDIR%%/;
}
location /test {
image_filter test;
alias %%TESTDIR%%/;
location /test/off {
image_filter off;
alias %%TESTDIR%%/;
}
}
location /resize {
image_filter resize 10 12;
alias %%TESTDIR%%/;
}
location /resize1 {
image_filter resize 10 -;
alias %%TESTDIR%%/;
}
location /resize2 {
image_filter resize - 12;
alias %%TESTDIR%%/;
}
location /resize_var {
image_filter resize $w $h;
alias %%TESTDIR%%/;
}
location /rotate {
image_filter rotate 90;
alias %%TESTDIR%%/;
}
location /rotate_var {
image_filter rotate $arg_r;
alias %%TESTDIR%%/;
}
location /crop {
image_filter crop 60 80;
alias %%TESTDIR%%/;
}
location /crop_var {
image_filter crop $arg_w $arg_h;
alias %%TESTDIR%%/;
}
location /crop_rotate {
image_filter crop $arg_w $arg_h;
image_filter rotate $arg_r;
alias %%TESTDIR%%/;
}
location /resize_rotate {
image_filter resize $w $h;
image_filter rotate $arg_r;
alias %%TESTDIR%%/;
location /resize_rotate/resize {
image_filter resize 10 12;
alias %%TESTDIR%%/;
}
}
location /interlaced {
image_filter resize 10 12;
image_filter_interlace on;
alias %%TESTDIR%%/;
}
location /nontransparent {
image_filter resize 10 12;
image_filter_transparency off;
alias %%TESTDIR%%/;
}
location /quality {
image_filter resize 10 12;
image_filter_jpeg_quality 50;
alias %%TESTDIR%%/;
}
location /quality_var {
image_filter resize 10 12;
image_filter_jpeg_quality $arg_q;
alias %%TESTDIR%%/;
location /quality_var/quality {
image_filter_jpeg_quality 60;
alias %%TESTDIR%%/;
}
}
location /buffer {
image_filter test;
image_filter_buffer 1k;
alias %%TESTDIR%%/;
}
location /proxy_buffer {
image_filter rotate 90;
image_filter_buffer 20;
proxy_pass http://127.0.0.1:8081/;
proxy_buffering off;
proxy_buffer_size 512;
}
}
}
EOF
my $im = new GD::Image(100, 120);
my $white = $im->colorAllocate(255, 255, 255);
my $black = $im->colorAllocate(0, 0, 0);
$im->transparent($white);
$im->rectangle(0, 0, 99, 99, $black);
$t->write_file('jpeg', $im->jpeg);
$t->write_file('gif', $im->gif);
$t->write_file('png', $im->png);
$t->write_file('txt', 'SEE-THIS');
$t->run_daemon(\&http_daemon, $t);
$t->run()->waitforsocket('127.0.0.1:' . port(8081));
###############################################################################
like(http_head('/test/gif'), qr/200 OK/, 'test');
like(http_head('/test/gif'), qr!Content-Type: image/gif!, 'test content-type');
like(http_get('/test/txt'), qr/415 Unsupported/, 'test fail');
like(http_get('/test/off/txt'), qr/SEE-THIS/, 'off');
is(http_get_body('/size/txt'), '{}' . CRLF, 'size wrong type');
like(http_head('/size/txt'), qr!Content-Type: application/json!,
'size content-type');
like(http_get('/size/jpeg'), qr/"width": 100/, 'size width');
like(http_get('/size/jpeg'), qr/"height": 120/, 'size height');
like(http_get('/size/jpeg'), qr/"type": "jpeg"/, 'size jpeg');
like(http_get('/size/gif'), qr/"type": "gif"/, 'size gif');
like(http_get('/size/png'), qr/"type": "png"/, 'size png');
is(gif_size('/resize/gif'), '10 12', 'resize');
is(gif_size('/resize1/gif'), '10 12', 'resize 1');
is(gif_size('/resize2/gif'), '10 12', 'resize 2');
is(gif_size('/resize_var/gif?w=10&h=12'), '10 12', 'resize var');
is(gif_size('/resize_var/gif?w=10'), '10 12', 'resize var 1');
is(gif_size('/resize_var/gif?h=12'), '10 12', 'resize var 2');
is(gif_size('/rotate/gif?r=90'), '120 100', 'rotate');
is(gif_size('/rotate_var/gif?r=180'), '100 120', 'rotate var 1');
is(gif_size('/rotate_var/gif?r=270'), '120 100', 'rotate var 2');
$im = GD::Image->newFromGifData(http_get_body('/gif'));
is($im->interlaced, 0, 'gif interlaced off');
is($im->transparent, 0, 'gif transparent white');
SKIP: {
skip 'broken/unknown libgd', 1
unless has_gdversion('2.1.0') or $ENV{TEST_NGINX_UNSAFE};
$im = GD::Image->newFromGifData(http_get_body('/interlaced/gif'));
is($im->interlaced, 1, 'gif interlaced on');
}
$im = GD::Image->newFromGifData(http_get_body('/nontransparent/gif'));
is($im->transparent, -1, 'gif transparent loss');
$im = GD::Image->newFromPngData(http_get_body('/png'));
is($im->interlaced, 0, 'png interlaced off');
is($im->transparent, 0, 'png transparent white');
# this test produces libpng warning on STDERR:
# "Interlace handling should be turned on when using png_read_image"
SKIP: {
skip 'can wedge nginx with SIGPIPE', 1 unless $ENV{TEST_NGINX_UNSAFE};
$im = GD::Image->newFromPngData(http_get_body('/interlaced/png'));
is($im->interlaced, 1, 'png interlaced on');
}
$im = GD::Image->newFromPngData(http_get_body('/nontransparent/png'));
is($im->transparent, -1, 'png transparent loss');
like(http_get('/resize/jpeg'), qr/quality = 75/, 'quality default');
like(http_get('/quality/jpeg'), qr/quality = 50/, 'quality');
like(http_get('/quality_var/jpeg?q=40'), qr/quality = 40/, 'quality var');
like(http_get('/quality_var/quality/jpeg?q=40'), qr/quality = 60/,
'quality nested');
is(gif_size('/crop/gif'), '60 80', 'crop');
is(gif_size('/crop_var/gif?w=10&h=20'), '10 20', 'crop var');
is(gif_size('/crop_rotate/gif?w=5&h=6&r=90'), '5 5', 'rotate before crop');
is(gif_size('/resize_rotate/gif?w=5&h=6&r=90'), '6 5', 'rotate after resize');
is(gif_size('/resize_rotate/resize/gif??w=5&h=6&r=90'), '10 12',
'resize rotate nested');
like(http_get('/buffer/jpeg'), qr/415 Unsupported/, 'small buffer');
isnt(http_get('/proxy_buffer/jpeg'), undef, 'small buffer proxy');
###############################################################################
sub gif_size {
join ' ', unpack("x6v2", http_get_body(@_));
}
sub http_get_body {
my ($uri) = @_;
return undef if !defined $uri;
my $text = http_get($uri);
if ($text !~ /(.*?)\x0d\x0a?\x0d\x0a?(.*)/ms) {
return undef;
}
return $2;
}
sub has_gdversion {
my ($need) = @_;
my $v_str = `gdlib-config --version 2>&1`
|| eval { GD::VERSION_STRING() } or return 0;
($v_str) = $v_str =~ m!^([0-9.]+)!m or return 0;
my @v = split(/\./, $v_str);
my ($n, $v);
for $n (split(/\./, $need)) {
$v = shift @v || 0;
return 0 if $n > $v;
return 1 if $v > $n;
}
return 1;
}
###############################################################################
# serve static files without Content-Length
sub http_daemon {
my ($t) = @_;
my $server = IO::Socket::INET->new(
Proto => 'tcp',
LocalHost => '127.0.0.1',
LocalPort => port(8081),
Listen => 5,
Reuse => 1
)
or die "Can't create listening socket: $!\n";
local $SIG{PIPE} = 'IGNORE';
while (my $client = $server->accept()) {
$client->autoflush(1);
my $headers = '';
my $uri = '';
while (<$client>) {
$headers .= $_;
last if (/^\x0d?\x0a?$/);
}
next if $headers eq '';
$uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
my $data = $t->read_file($uri);
print $client <<EOF;
HTTP/1.1 200 OK
Connection: close
$data
EOF
} continue {
close $client;
}
}
###############################################################################