File Coverage

blib/lib/OpenID/Login/URI.pm
Criterion Covered Total %
statement 63 77 81.8
branch 15 32 46.8
condition 2 6 33.3
subroutine 8 9 88.8
pod 2 2 100.0
total 90 126 71.4


line stmt bran cond sub pod time code
1             package OpenID::Login::URI;
2             {
3             $OpenID::Login::URI::VERSION = '0.1.2';
4             }
5              
6             # ABSTRACT: OpenID Identifier validation and encoding for OpenID::Login.
7              
8 4     4   24 use strict;
  4         9  
  4         160  
9              
10 4     4   25 use URI;
  4         8  
  4         108  
11 4     4   24 use List::MoreUtils qw(none any);
  4         9  
  4         4390  
12              
13             sub _build_url_regexp {
14 4     4   11 my $class = shift;
15 4         7 my $digit = q{[0-9]};
16 4         9 my $upalpha = q{[A-Z]};
17 4         8 my $lowalpha = q{[a-z]};
18 4         13 my $alpha = qq{(?:$lowalpha|$upalpha)};
19 4         13 my $alphanum = qq{(?:$alpha|$digit)};
20 4         9 my $hex = qq{(?:$digit|[A-Fa-f])};
21 4         10 my $escaped = qq{%$hex$hex};
22 4         30 my $mark = q{[-_.!~*'()]};
23 4         12 my $unreserved = qq{(?:$alphanum|$mark)};
24 4         7 my $reserved = q{[;/?:@&=+$,]};
25 4         14 my $uric = qq{(?:$reserved|$unreserved|$escaped)};
26 4         11 my $query = qq{$uric*};
27 4         14 my $pchar = qq{(?:$unreserved|$escaped|} . q{[:@&=+$,])};
28 4         12 my $param = qq{$pchar*};
29 4         10 my $segment = qq{$pchar*(?:;$param)*};
30 4         11 my $path_segments = qq{$segment(?:/$segment)*};
31 4         12 my $abs_path = qq{/$path_segments};
32 4         8 my $port = qq{$digit*};
33 4         10 my $IPv4address = qq{$digit+\\.$digit+\\.$digit+\\.$digit+};
34 4         17 my $toplabel = qq{(?:$alpha|$alpha(?:$alphanum|-)*$alphanum)};
35 4         15 my $domainlabel = qq{(?:$alphanum|$alphanum(?:$alphanum|-)*$alphanum)};
36 4         11 my $hostname = qq{(?:$domainlabel\\.)*$toplabel\\.?};
37 4         12 my $host = qq{(?:$hostname|$IPv4address)};
38 4         11 my $fragment = qq{$uric*};
39 4         17 my $pattern = qq{https?://$host(?::$port)?(?:$abs_path(?:\\?$query)?)?(?:#$fragment)?};
40 4         16 return $pattern;
41             }
42              
43             my $REGEX = __PACKAGE__->_build_url_regexp();
44              
45              
46             sub is_uri {
47 12     12 1 22 my $class = shift;
48 12         21 my $uri = shift;
49 12         1049 return $uri =~ /^$REGEX$/o;
50             }
51              
52              
53             sub normalize {
54 12     12 1 25 my $class = shift;
55 12         22 my $uri = shift;
56              
57 12         72 my $u = URI->new($uri);
58 12 50       31007 return unless $u->scheme;
59 12 50   19   973 return if ( none { $_ eq $u->scheme } qw(http https) );
  19         140  
60 12 50 33     288 return unless $u->can('host') && $u->host;
61              
62 12         542 my $path = $class->_remove_dot_segments( $u->path );
63 12 100       39 $path = '/' if length($path) == 0;
64 12         43 $u->path($path);
65              
66 12         425 my $u_str = $u->canonical->as_string;
67 12         1130 $u_str =~ s/(%[a-fA-F0-9]{2})/uc $class->_encode($1)/eg;
  0         0  
68 12         92 return $u_str;
69             }
70              
71             sub _encode {
72 0     0   0 my ( $class, $u ) = @_;
73 0         0 my $num = substr( $u, 1 );
74 0         0 my $packed = pack( 'H*', $num );
75 0 0       0 return $packed =~ /[A-Za-z0-9._~-]/ ? $packed : $u;
76             }
77              
78             sub _remove_dot_segments {
79 12     12   171 my ( $class, $path ) = @_;
80 12         21 my @result_segments;
81 12         42 while ( length($path) > 0 ) {
82 8 50 33     113 if ( $path =~ m!^\.\./! ) {
    50          
    50          
    50          
    50          
    50          
    50          
83 0         0 $path = substr( $path, 3 );
84             } elsif ( $path =~ m!^\./! ) {
85 0         0 $path = substr( $path, 2 );
86             } elsif ( $path =~ m!^/\./! ) {
87 0         0 $path = substr( $path, 2 );
88             } elsif ( $path eq q{/.} ) {
89 0         0 $path = q{/};
90             } elsif ( $path =~ m!^/\.\./! ) {
91 0         0 $path = substr( $path, 3 );
92 0 0       0 pop(@result_segments) if @result_segments > 0;
93             } elsif ( $path eq q{/..} ) {
94 0         0 $path = q{/};
95 0 0       0 pop(@result_segments) if @result_segments > 0;
96             } elsif ( $path eq q{..} || $path eq q{.} ) {
97 0         0 $path = q{};
98             } else {
99 8         14 my $i = 0;
100 8 50       34 $i = 1 if substr( $path, 0, 1 ) eq q{/};
101 8         16 $i = index( $path, q{/}, $i );
102 8 100       22 $i = length($path) unless $i >= 0;
103 8         22 push( @result_segments, substr( $path, 0, $i ) );
104 8         28 $path = substr( $path, $i );
105             }
106             }
107 12         45 return join( '', @result_segments );
108             }
109              
110             1;
111              
112              
113              
114             =pod
115              
116             =head1 NAME
117              
118             OpenID::Login::URI - OpenID Identifier validation and encoding for OpenID::Login.
119              
120             =head1 VERSION
121              
122             version 0.1.2
123              
124             =head1 METHODS
125              
126             =head2 is_uri
127              
128             Determines if supplied parameter is an uri.
129              
130             =head2 normalize
131              
132             Normalizes and encodes an supplied uri if necessary.
133              
134             =head1 AUTHOR
135              
136             Holger Eiboeck <realholgi@cpan.org>
137              
138             =head1 COPYRIGHT AND LICENSE
139              
140             This software is copyright (c) 2013 by Holger Eiboeck.
141              
142             This is free software; you can redistribute it and/or modify it under
143             the same terms as the Perl 5 programming language system itself.
144              
145             =cut
146              
147              
148             __END__