File Coverage

blib/lib/Net/SSLeay/OO/Error.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1              
2             package Net::SSLeay::OO::Error;
3              
4 3     3   17 use Net::SSLeay;
  3         6  
  3         165  
5 3     3   240012 use Moose;
  0            
  0            
6              
7             has 'err' => isa => 'Int',
8             is => 'ro',
9             required => 1,
10             default => sub {
11             Net::SSLeay::ERR_get_error
12             or die "no OpenSSL error to get";
13             };
14              
15             sub ssl_error_pending {
16             Net::SSLeay::ERR_peek_error;
17             }
18              
19             has 'error_code' => isa => "Int",
20             is => "ro",
21             ;
22              
23             has 'library_name' => isa => "Str",
24             is => "ro",
25             ;
26              
27             has 'function_name' => isa => "Str",
28             is => "ro",
29             ;
30              
31             has 'reason_string' => isa => "Str",
32             is => "ro",
33             ;
34              
35             has 'next' => isa => __PACKAGE__,
36             is => "ro",
37             ;
38              
39             sub BUILD {
40             my $self = shift;
41             my $ssl_error = $self->error_string;
42             ( undef, my @fields ) = split ":", $ssl_error, 5;
43             $self->{error_code} ||= hex( shift @fields );
44             $self->{library_name} ||= shift @fields;
45             $self->{function_name} ||= shift @fields;
46             $self->{reason_string} ||= shift @fields;
47              
48             # OpenSSL throws an entire stack backtrace, so capture all the
49             # outstanding SSL errors and chain them off this one.
50             if (ssl_error_pending) {
51             $self->{next} = ( ref $self )->new();
52             }
53             }
54              
55             has 'message' => isa => "Str",
56             is => "rw",
57             ;
58              
59             sub die_if_ssl_error {
60             my $message = shift;
61             if (ssl_error_pending) {
62             die __PACKAGE__->new( message => $message );
63             }
64             }
65              
66             sub as_string {
67             my $self = shift;
68             my $message = $self->message;
69             if ($message) {
70             unless ( $message =~ / / ) {
71             $message = "During `$message'";
72             }
73             $message .= ": ";
74             }
75             else {
76             $message = "";
77             }
78             my $reason_string = $self->reason_string;
79             my $result = do {
80             if ( $reason_string eq "system lib" ) { # FIXME: lang
81             sprintf( "%s%.8x: trace: %s (%s)",
82             $message, $self->error_code,
83             $self->function_name, $self->library_name );
84             }
85             else {
86             sprintf("%sOpenSSL error %.8x: %s during %s (%s)",
87             $message, $self->error_code,
88             $self->reason_string, $self->function_name,
89             $self->library_name
90             );
91             }
92             };
93             if ( $self->next ) {
94             $result .= "\n" . " then " . $self->next->as_string;
95             }
96             if ( $result =~ m{\n} and $result !~ m{\n\Z} ) {
97             $result .= "\n";
98             }
99             $result;
100             }
101              
102             use overload
103             '""' => \&as_string,
104             ;
105              
106             use Sub::Exporter -setup =>
107             { exports => [qw(die_if_ssl_error ssl_error_pending)], };
108              
109             use Net::SSLeay::OO::Functions sub {
110             my $code = shift;
111             sub {
112             my $self = shift;
113             $code->( $self->err, @_ );
114             }
115             };
116              
117             1;
118              
119             __END__
120              
121             =head1 NAME
122              
123             Net::SSLeay::OO::Error - encapsulated SSLeay errors
124              
125             =head1 SYNOPSIS
126              
127             use Scalar::Util qw(blessed);
128             eval {
129             $ctx->use_PrivateKey_file($filename, FILETYPE_PEM);
130             };
131             my $error = $@;
132             if (blessed $error and
133             ( $error->error_code == 0x0B080074 or
134             $error->reason_string =~ /key.*mismatch/i ) ) {
135             # deal with some known error condition differently..
136             die "Private key file mismatches certificate file, did "
137             ."you update both settings?";
138             }
139             elsif ($error) {
140             die $error;
141             }
142              
143             # if you need to manually check for errors ever
144             use Net::SSLeay::OO::Error qw(die_if_ssl_error ssl_error_pending);
145             die_if_ssl_error("Initialization");
146              
147             =head1 DESCRIPTION
148              
149             Unlike L<Net::SSLeay>, with L<Net::SSLeay::OO> functions, if an error
150             occurs in a low level library an exception is raised via C<die>.
151              
152             OpenSSL has an 'error queue', which normally represents something like
153             a stack trace indicating the context of the error. The first error
154             will be the "deepest" error and usually has the most relevant error
155             message. To represent this, the Net::SSLeay::OO::Error object has a
156             B<next> property, which represents a level further up the exception
157             heirarchy.
158              
159             =head1 METHODS
160              
161             The following methods are defined (some via L<Moose> attributes):
162              
163             =over
164              
165             =item B<error_string()>
166              
167             Returns the error string from OpenSSL.
168              
169             =item B<as_string()>
170              
171             Returns the error string, turned into a marginally more user-friendly
172             message. Also available as the overloaded '""' operator (ie, when
173             interpreted as a string you will get a message)
174              
175             =item B<error_code()>
176              
177             A fixed error code corresponding to the error.
178              
179             =item B<reason_string()>
180              
181             The human-readable part, or (apparently) "system lib" if the error is
182             part of a stack trace.
183              
184             =item B<library_name()>
185              
186             =item B<function_name()>
187              
188             Where the error occurred, or where this part of the stack trace
189             applies.
190              
191             =item B<next()>
192              
193             The next (shallower) Net::SSLeay::OO::Error object, corresponding to the
194             next level up the stack trace.
195              
196             =item B<message( [$message] )>
197              
198             The caller-supplied message that this error will be prefixed with. If
199             this is a single word (no whitespace) then it will be printed as
200             C<During `$message':>.
201              
202             =back
203              
204             =head1 FUNCTIONS
205              
206             These functions are available for export.
207              
208             =over
209              
210             =item B<die_if_ssl_error($message)>
211              
212             This is similar to L<Net::SSLeay>'s function of the same name, except;
213              
214             =over
215              
216             =item 1.
217              
218             The entire error queue is cleared, and wrapped into a single
219             chain of exception objects
220              
221             =item 2.
222              
223             The message is parceled to be hopefully a little more human-readable.
224              
225             =back
226              
227             Here is an example, an error raised during the test suite script
228             F<t/03-ssl.t>:
229              
230             During `use_certificate_file': OpenSSL error 02001002: No such file or directory during fopen (system library)
231             then 20074002: trace: FILE_CTRL (BIO routines)
232             then 140c8002: trace: SSL_use_certificate_file (SSL routines)
233              
234             The function was called as:
235             C<die_if_ssl_error("use_certificate_file")>
236              
237             The strings returned from OpenSSL as a "human readable" error messages
238             were:
239              
240             error:02001002:system library:fopen:No such file or directory
241             error:20074002:BIO routines:FILE_CTRL:system lib
242             error:140C8002:SSL routines:SSL_use_certificate_file:system lib
243              
244             =item B<ssl_error_pending()>
245              
246             Returns a non-zero integer if there is an error pending. To fetch it,
247             just create a new L<Net::SSLeay::OO::Error> object.
248              
249             =back
250              
251             =head1 AUTHOR
252              
253             Sam Vilain, L<samv@cpan.org>
254              
255             =head1 COPYRIGHT
256              
257             Copyright (C) 2009 NZ Registry Services
258              
259             This program is free software: you can redistribute it and/or modify
260             it under the terms of the Artistic License 2.0 or later. You should
261             have received a copy of the Artistic License the file COPYING.txt. If
262             not, see <http://www.perlfoundation.org/artistic_license_2_0>
263              
264             =head1 SEE ALSO
265              
266             L<Net::SSLeay::OO>
267              
268             =cut
269              
270             # Local Variables:
271             # mode:cperl
272             # indent-tabs-mode: t
273             # cperl-continued-statement-offset: 8
274             # cperl-brace-offset: 0
275             # cperl-close-paren-offset: 0
276             # cperl-continued-brace-offset: 0
277             # cperl-continued-statement-offset: 8
278             # cperl-extra-newline-before-brace: nil
279             # cperl-indent-level: 8
280             # cperl-indent-parens-as-block: t
281             # cperl-indent-wrt-brace: nil
282             # cperl-label-offset: -8
283             # cperl-merge-trailing-else: t
284             # End:
285             # vim: filetype=perl:noexpandtab:ts=3:sw=3