package TestError::runtime; use strict; use warnings FATAL => 'all'; use Apache2::RequestRec (); use Apache2::RequestIO (); use Apache2::Connection (); use APR::Socket (); use APR::Status (); use Apache::TestUtil; use Apache2::Const -compile => qw(OK); use APR::Const -compile => qw(EACCES); use constant SIZE => 2048; sub handler { my $r = shift; my $socket = $r->connection->client_socket; my $args = $r->args; $r->content_type('text/plain'); # set timeout to 0 to make sure that any socket read call will # fail $socket->timeout_set(0); no strict 'refs'; $args->($r, $socket); return Apache2::Const::OK; } sub overload_test { my ($r, $socket) = @_; eval { mp_error($socket) }; die "there should have been an exception" unless $@; die "the exception should have been an APR::Error object" unless ref $@ eq 'APR::Error'; # == && != (expecting an EAGAIN error) die "APR::Status is broken" unless APR::Status::is_EAGAIN($@); die "'==' overload is broken" unless $@ == $@; die "'!=' overload is broken" unless $@ != APR::Const::EACCES; die "'!=' overload is broken" unless APR::Const::EACCES != $@; die "'!=' overload is broken" if $@ != $@; # XXX: add more overload tests $r->print("ok overload_test"); } sub plain_mp_error { my ($r, $socket) = @_; t_server_log_error_is_expected(); mp_error($socket); } sub plain_non_mp_error { my ($r, $socket) = @_; t_server_log_error_is_expected(); non_mp_error($socket); } sub die_hook_confess_mp_error { my ($r, $socket) = @_; local $SIG{__DIE__} = \&APR::Error::confess; t_server_log_error_is_expected(); mp_error($socket); } sub die_hook_confess_non_mp_error { my ($r, $socket) = @_; local $SIG{__DIE__} = \&APR::Error::confess; t_server_log_error_is_expected(); non_mp_error($socket); } sub die_hook_custom_mp_error { my ($r, $socket) = @_; local $SIG{__DIE__} = sub { die "custom die hook: $_[0]" }; t_server_log_error_is_expected(); mp_error($socket); } sub die_hook_custom_non_mp_error { my ($r, $socket) = @_; local $SIG{__DIE__} = sub { die "custom die hook: $_[0]" }; t_server_log_error_is_expected(); non_mp_error($socket); } sub eval_block_mp_error { my ($r, $socket) = @_; # throw in some retry attempts my $tries = 0; RETRY: eval { mp_error($socket) }; if ($@ && ref($@) && APR::Status::is_EAGAIN($@)) { if ($tries++ < 3) { goto RETRY; } else { $r->print("ok eval_block_mp_error"); } } else { die "eval block has failed: $@"; } } sub eval_string_mp_error { my ($r, $socket) = @_; eval '$socket->recv(my $buffer, SIZE)'; if ($@ && ref($@) && APR::Status::is_EAGAIN($@)) { $r->print("ok eval_string_mp_error"); } else { die "eval string has failed: $@"; } } sub eval_block_non_mp_error { my ($r, $socket) = @_; eval { non_mp_error($socket) }; if ($@ && !ref($@)) { $r->print("ok eval_block_non_mp_error"); } else { die "eval eval_non_mp_error has failed: $@"; } } sub eval_block_non_error { my ($r, $socket) = @_; eval { 1; }; if ($@) { die "eval eval_block_non_mp_error has failed"; } $r->print("ok eval_block_non_error"); } sub non_mp_error { no_such_func(); } # fails because of the timeout set earlier in the handler sub mp_error { my $socket = shift; $socket->recv(my $buffer, SIZE); } 1; __END__