CGI-Info
view release on metacpan or search on metacpan
t/extended_tests.t view on Meta::CPAN
my $proto = $info->protocol();
ok(!defined($proto), 'protocol() returns undef when indeterminate');
my $msgs = $info->messages();
ok(defined($msgs) && scalar @{$msgs} > 0,
'undetermined protocol with REMOTE_ADDR logs a warning');
};
# ============================================================
# 8. protocol() â SERVER_PROTOCOL present but not HTTP/ prefix
# Branch: SERVER_PROTOCOL check fails, falls through to port check
# ============================================================
subtest 'protocol: non-HTTP SERVER_PROTOCOL does not return http' => sub {
reset_env();
$ENV{SERVER_PROTOCOL} = 'FTP/1.0';
{
my $guard = mock_scoped 'CGI::Info::getservbyport' => sub { return undef };
my $proto = CGI::Info->new()->protocol();
ok(!defined($proto) || $proto ne 'http',
'non-HTTP SERVER_PROTOCOL not returned as http');
}
};
# ============================================================
# 9. params() â HEAD request handled same as GET
# Branch: REQUEST_METHOD eq 'HEAD'
# ============================================================
subtest 'params: HEAD request parses QUERY_STRING like GET' => sub {
reset_env();
$ENV{GATEWAY_INTERFACE} = 'CGI/1.1';
$ENV{REQUEST_METHOD} = 'HEAD';
$ENV{QUERY_STRING} = 'x=1&y=2';
my $info = CGI::Info->new();
my $p = $info->params();
ok(defined $p, 'HEAD request returns params');
is($p->{x}, '1', 'x=1 parsed from HEAD');
is($p->{y}, '2', 'y=2 parsed from HEAD');
};
# ============================================================
# 10. params() â \\u0026 Unicode ampersand escape in QUERY_STRING
# Branch: $query =~ s/\\u0026/\&/g
# ============================================================
subtest 'params: \\u0026 unicode ampersand escape decoded' => sub {
reset_env();
$ENV{GATEWAY_INTERFACE} = 'CGI/1.1';
$ENV{REQUEST_METHOD} = 'GET';
$ENV{QUERY_STRING} = 'a=1\\u0026b=2';
my $info = CGI::Info->new();
my $p = $info->params();
ok(defined $p, 'params returned with \\u0026 encoded ampersand');
is($p->{a}, '1', 'a=1 parsed after \\u0026 decoded');
is($p->{b}, '2', 'b=2 parsed after \\u0026 decoded');
};
# ============================================================
# 11. params() â upload_dir not absolute => 500
# Branch: !File::Spec->file_name_is_absolute($self->{upload_dir})
# ============================================================
subtest 'params: multipart with relative upload_dir => 500' => sub {
reset_env();
$ENV{GATEWAY_INTERFACE} = 'CGI/1.1';
$ENV{REQUEST_METHOD} = 'POST';
$ENV{CONTENT_TYPE} = 'multipart/form-data; boundary=----b';
$ENV{CONTENT_LENGTH} = 100;
my $info = CGI::Info->new(upload_dir => 'relative/path');
my $p = eval { $info->params() };
ok(!$@, 'does not die on relative upload_dir');
ok(!defined($p), 'relative upload_dir returns undef');
is($info->status(), 500, 'relative upload_dir sets status 500');
};
# ============================================================
# 12. params() â upload_dir not a directory => 500
# Branch: !-d $self->{upload_dir}
# ============================================================
subtest 'params: multipart with upload_dir pointing to a file => 500' => sub {
reset_env();
my $tmp = File::Temp->new(UNLINK => 1);
my $file = $tmp->filename();
$ENV{GATEWAY_INTERFACE} = 'CGI/1.1';
$ENV{REQUEST_METHOD} = 'POST';
$ENV{CONTENT_TYPE} = 'multipart/form-data; boundary=----b';
$ENV{CONTENT_LENGTH} = 100;
my $info = CGI::Info->new(upload_dir => $file);
my $p = eval { $info->params() };
ok(!$@, 'does not die when upload_dir is a file not a dir');
ok(!defined($p), 'file-as-upload_dir returns undef');
is($info->status(), 500, 'file-as-upload_dir sets status 500');
};
# ============================================================
# 13. params() â upload_dir not inside tmpdir => 500
# Branch: upload_dir !~ /^\Q$tmpdir\E/
# ============================================================
subtest 'params: upload_dir outside tmpdir => 500' => sub {
reset_env();
my $outside = tempdir(CLEANUP => 1);
$ENV{GATEWAY_INTERFACE} = 'CGI/1.1';
$ENV{REQUEST_METHOD} = 'POST';
$ENV{CONTENT_TYPE} = 'multipart/form-data; boundary=----b';
$ENV{CONTENT_LENGTH} = 100;
# Make tmpdir() return something different from $outside by mocking
my $guard = mock_scoped 'CGI::Info::tmpdir' => sub { return '/nonexistent/tmpdir/xyz' };
my $info = CGI::Info->new(upload_dir => $outside);
my $p = eval { $info->params() };
ok(!$@, 'does not die when upload_dir outside tmpdir');
ok(!defined($p), 'upload_dir outside tmpdir returns undef');
is($info->status(), 500, 'upload_dir outside tmpdir sets status 500');
};
# ============================================================
# 14. params() â Params::Validate::Strict schema returns empty hash
# Branch: !(scalar keys %{$value}) after validate_strict
# ============================================================
subtest 'params: schema validation returning empty hash blocks param' => sub {
reset_env();
$ENV{GATEWAY_INTERFACE} = 'CGI/1.1';
$ENV{REQUEST_METHOD} = 'GET';
$ENV{QUERY_STRING} = 'score=999';
my $info = CGI::Info->new();
my $p = $info->params(allow => {
score => { type => 'integer', min => 0, max => 100 }
});
ok(!defined($p) || !defined($p->{score}),
'out-of-range value blocked by Params::Validate::Strict schema');
is($info->status(), 422, 'schema block sets status 422');
};
# ============================================================
# 15. param() â in_param recursion guard
# Branch: $self->{in_param} && $self->{allow} => delete allow temporarily
# A coderef allow that calls $obj->param() on the same instance
# ============================================================
subtest 'param: recursion guard prevents deep recursion in coderef validator' => sub {
reset_env();
$ENV{GATEWAY_INTERFACE} = 'CGI/1.1';
$ENV{REQUEST_METHOD} = 'GET';
$ENV{QUERY_STRING} = 'flag=1&score=50';
my $info = CGI::Info->new();
my $p = $info->params(allow => {
flag => qr/^[01]$/,
score => sub {
my ($key, $val, $obj) = @_;
# This calls param() recursively on the same object
# The in_param guard must prevent infinite recursion
my $flag = $obj->param('flag');
return defined($flag) && $flag && $val >= 0 && $val <= 100;
},
});
ok(!$@, 'recursive param() call in coderef does not cause infinite recursion');
ok(defined $p && defined $p->{score}, 'score validated via recursive param() call');
};
# ============================================================
# 16. is_mobile() â Sec-CH-UA-Mobile '?0' (not ?1, falls through)
# Branch: ch_ua_mobile ne '?1'
# ============================================================
subtest 'is_mobile: Sec-CH-UA-Mobile ?0 does not set mobile' => sub {
reset_env();
$ENV{HTTP_SEC_CH_UA_MOBILE} = '?0';
$ENV{HTTP_USER_AGENT} = 'Mozilla/5.0 (Windows NT 10.0)';
$ENV{REMOTE_ADDR} = '1.2.3.4';
( run in 1.072 second using v1.01-cache-2.11-cpan-b16cb0d3907 )