Skip to content

Commit

Permalink
Handle exceptions throwed by the user from callback
Browse files Browse the repository at this point in the history
  • Loading branch information
olegwtf committed Aug 31, 2017
1 parent d328a3a commit 252f2b7
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 6 deletions.
13 changes: 8 additions & 5 deletions lib/Mojo/SMTP/Client.pm
Expand Up @@ -146,7 +146,8 @@ sub send {
$delay->on(finish => sub {
if ($cb) {
my $r = $_[1];
if ($r->isa('Mojo::SMTP::Client::Exception')) {
unless ($r->isa('Mojo::SMTP::Client::Response')) {
# some error occured, which throwed an exception
$r = Mojo::SMTP::Client::Response->new('', error => $r);
}

Expand Down Expand Up @@ -238,7 +239,7 @@ sub _make_cmd_steps {
sub {
eval { $self->{resp_checker}->(@_); $_[1]->{checked} = 1 };
if (my $e = $@) {
die $e unless $e->error->isa('Mojo::SMTP::Client::Exception::Response');
die $e unless $e->isa('Mojo::SMTP::Client::Response');
my $delay = shift;

$self->{stream}->start if !$prepend && $mi == $#cmd; # XXX: _read_response may stop stream
Expand Down Expand Up @@ -588,7 +589,8 @@ C<Mojo::SMTP::Client> inherits all events from L<Mojo::EventEmitter> and can emi
$smtp->inactivity_timeout(5*60);
});
Emitted whenever a new connection is about to start.
Emitted whenever a new connection is about to start. You can interrupt sending by dying or throwing an exception
from this callback, C<error> attribute of the response will contain corresponding error.
=head2 response
Expand All @@ -601,7 +603,8 @@ Emitted whenever a new connection is about to start.
});
Emitted for each SMTP response from the server. C<$cmd> is a command L<constant|/CONSTANTS> for which this
response was sent. C<$resp> is L<Mojo::SMTP::Client::Response> object.
response was sent. C<$resp> is L<Mojo::SMTP::Client::Response> object. You can interrupt sending by dying or
throwing an exception from this callback, C<error> attribute of the response will contain corresponding error.
=head1 ATTRIBUTES
Expand Down Expand Up @@ -751,7 +754,7 @@ C<$resp-E<gt>message> (string).
For blocking usage C<$resp> will be returned as result of C<$smtp-E<gt>send> call. C<$resp> is the same as for
non-blocking result. If L</autodie> attribute has true value C<send> will throw an exception on any error.
Which will be one of C<Mojo::SMTP::Client::Exception::*>.
Which will be one of C<Mojo::SMTP::Client::Exception::*> or an error throwed by the user inside <start> or L<connect> callback.
B<Note>. For SMTP protocol it is important to send commands in certain order. Also C<send> will send all commands in order you are
specified. So, it is important to pass arguments to C<send> in right order. For basic usage this will always be:
Expand Down
3 changes: 2 additions & 1 deletion lib/Mojo/SMTP/Client/Response.pm
Expand Up @@ -87,7 +87,8 @@ C<Mojo::SMTP::Client::Response> implements the following attributes
=head2 error
Error for this response. Should be one of C<Mojo::SMTP::Client::Exception::*>
defined in L<Mojo::SMTP::Client::Exception>. Default is C<undef>.
defined in L<Mojo::SMTP::Client::Exception> or error throwed by the user from callback.
Default is C<undef>.
=head1 METHODS
Expand Down
24 changes: 24 additions & 0 deletions t/02_smtp.t
@@ -1,6 +1,7 @@
use strict;
use Test::More;
use Mojo::SMTP::Client;
use Mojo::Exception;
use Socket 'CRLF';
use lib 't/lib';
use Utils;
Expand Down Expand Up @@ -60,4 +61,27 @@ isa_ok($e, 'Mojo::SMTP::Client::Exception::Response');
close $sock;
kill 15, $pid;

# 4
($pid, $sock, $host, $port) = Utils::make_smtp_server();
$smtp = Mojo::SMTP::Client->new(address => $host, port => $port, autodie => 1);
syswrite($sock, join(CRLF, '220 host.net', '220 hello ok', '220 from ok', '220 to ok', '220 quit ok').CRLF);

$smtp->on(response => sub {
my $cmd = $_[1];

if ($cmd == Mojo::SMTP::Client::CMD_EHLO) {
Mojo::Exception->throw("Throwed from response callback");
}
});

eval {
$smtp->send(hello => 'mymail.host', from => '', to => 'jorik@gmail.com', quit => 1);
};
my $e = $@;
is(ref $e, 'Mojo::Exception', 'got right exception');
is($e->message, 'Throwed from response callback', 'with right message');

close $sock;
kill 15, $pid;

done_testing;
66 changes: 66 additions & 0 deletions t/03_smtp_nb.t
Expand Up @@ -459,6 +459,72 @@ $loop->reactor->remove($sock);
close $sock;
kill 15, $pid;

# 7
($pid, $sock, $host, $port) = Utils::make_smtp_server();
$smtp = Mojo::SMTP::Client->new(address => $host, port => $port, hello => 'dragon-host.net');
$smtp->on(start => sub {
die "error from start callback\n";
});

$smtp->send(
from => 'abc@mail.ru',
to => 'xyz@mail.ru',
data => 'smth useless',
sub {
my $resp = pop;

ok($resp->error, "Got error from the `start' callback");
is($resp->error, "error from start callback\n", "Got right error");

$loop->stop;
}
);

$loop->start;
close $sock;
kill 15, $pid;

# 8
($pid, $sock, $host, $port) = Utils::make_smtp_server();
$smtp = Mojo::SMTP::Client->new(address => $host, port => $port, hello => 'dragon-host.net');
$smtp->on(response => sub {
my $cmd = $_[1];

if ($cmd == Mojo::SMTP::Client::CMD_EHLO) {
die "I don't like you\n";
}
});

$i = 0;

$smtp->send(
from => 'abc@mail.ru',
to => 'xyz@mail.ru',
data => 'smth useless',
sub {
my $resp = pop;

ok($resp->error, "Got error from the `response' callback");
is($resp->error, "I don't like you\n", "Got right error");
is($i, 2, "connect -> EHLO -> die");

$loop->stop;
}
);

$loop->reactor->io($sock => sub {
my $cmd = <$sock>;
return unless $cmd; # socket closed
syswrite($sock, '220 OK'.CRLF);
$i++;
});

$loop->reactor->watch($sock, 1, 0);
$loop->start;
$loop->reactor->remove($sock);
close $sock;
kill 15, $pid;

done_testing;

__DATA__
Expand Down

0 comments on commit 252f2b7

Please sign in to comment.