| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package URI; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 41 |  |  | 41 |  | 2192652 | use strict; | 
|  | 41 |  |  |  |  | 377 |  | 
|  | 41 |  |  |  |  | 1198 |  | 
| 4 | 41 |  |  | 41 |  | 202 | use warnings; | 
|  | 41 |  |  |  |  | 116 |  | 
|  | 41 |  |  |  |  | 2649 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | our $VERSION = '5.20'; | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | # 1=version 5.10 and earlier; 0=version 5.11 and later | 
| 9 | 41 | 100 |  | 41 |  | 308 | use constant HAS_RESERVED_SQUARE_BRACKETS => $ENV{URI_HAS_RESERVED_SQUARE_BRACKETS} ? 1 : 0; | 
|  | 41 |  |  |  |  | 87 |  | 
|  | 41 |  |  |  |  | 12196 |  | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | our ($ABS_REMOTE_LEADING_DOTS, $ABS_ALLOW_RELATIVE_SCHEME, $DEFAULT_QUERY_FORM_DELIMITER); | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | my %implements;  # mapping from scheme to implementor class | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | # Some "official" character classes | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | our $reserved   = HAS_RESERVED_SQUARE_BRACKETS ? q(;/?:@&=+$,[]) : q(;/?:@&=+$,); | 
| 18 |  |  |  |  |  |  | our $mark       = q(-_.!~*'());                                    #'; emacs | 
| 19 |  |  |  |  |  |  | our $unreserved = "A-Za-z0-9\Q$mark\E"; | 
| 20 |  |  |  |  |  |  | our $uric       = quotemeta($reserved) . $unreserved . "%"; | 
| 21 |  |  |  |  |  |  | our $uric4host  = $uric . ( HAS_RESERVED_SQUARE_BRACKETS ? '' : quotemeta( q([]) ) ); | 
| 22 |  |  |  |  |  |  | our $uric4user  = quotemeta( q{!$'()*,;:._~%-+=%&} ) . "A-Za-z0-9" . ( HAS_RESERVED_SQUARE_BRACKETS ? quotemeta( q([]) ) : '' ); # RFC-3987: iuserinfo w/o UTF | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | our $scheme_re  = '[a-zA-Z][a-zA-Z0-9.+\-]*'; | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | # These schemes don't have an IPv6+ address part. | 
| 27 |  |  |  |  |  |  | our $schemes_without_host_part_re = 'data|ldapi|urn|sqlite|sqlite3'; | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | # These schemes can have an IPv6+ authority part: | 
| 30 |  |  |  |  |  |  | #     file, ftp, gopher, http, https, ldap, ldaps, mms, news, nntp, nntps, pop, rlogin, rtsp, rtspu, rsync, sip, sips, snews, | 
| 31 |  |  |  |  |  |  | #     telnet, tn3270, ssh, sftp | 
| 32 |  |  |  |  |  |  | #     (all DB URIs, i.e. cassandra, couch, couchdb, etc.), except 'sqlite:', 'sqlite3:'. Others? | 
| 33 |  |  |  |  |  |  | #MAINT: URI has no test coverage for DB schemes | 
| 34 |  |  |  |  |  |  | #MAINT: decoupling - perhaps let each class decide itself by defining a member function 'scheme_has_authority_part()'? | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | #MAINT: 'mailto:' needs special treatment for IPv* addresses / RFC 5321 (4.1.3). Until then: restore all '[', ']' | 
| 37 |  |  |  |  |  |  | # These schemes need fallback to previous (<= 5.10) encoding until a specific handler is available. | 
| 38 |  |  |  |  |  |  | our $fallback_schemes_re = 'mailto'; | 
| 39 |  |  |  |  |  |  |  | 
| 40 | 41 |  |  | 41 |  | 313 | use Carp (); | 
|  | 41 |  |  |  |  | 87 |  | 
|  | 41 |  |  |  |  | 792 |  | 
| 41 | 41 |  |  | 41 |  | 17641 | use URI::Escape (); | 
|  | 41 |  |  |  |  | 142 |  | 
|  | 41 |  |  |  |  | 4316 |  | 
| 42 |  |  |  |  |  |  |  | 
| 43 | 852 |  |  | 852 |  | 53524 | use overload ('""'     => sub { ${$_[0]} }, | 
|  | 852 |  |  |  |  | 3934 |  | 
| 44 | 31 |  |  | 31 |  | 150 | '=='     => sub { _obj_eq(@_) }, | 
| 45 | 1 |  |  | 1 |  | 994 | '!='     => sub { !_obj_eq(@_) }, | 
| 46 | 41 |  |  |  |  | 441 | fallback => 1, | 
| 47 | 41 |  |  | 41 |  | 50412 | ); | 
|  | 41 |  |  |  |  | 42550 |  | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | # Check if two objects are the same object | 
| 50 |  |  |  |  |  |  | sub _obj_eq { | 
| 51 | 32 |  |  | 32 |  | 110 | return overload::StrVal($_[0]) eq overload::StrVal($_[1]); | 
| 52 |  |  |  |  |  |  | } | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  | sub new | 
| 55 |  |  |  |  |  |  | { | 
| 56 | 1216 |  |  | 1216 | 1 | 65683 | my($class, $uri, $scheme) = @_; | 
| 57 |  |  |  |  |  |  |  | 
| 58 | 1216 | 50 |  |  |  | 3010 | $uri = defined ($uri) ? "$uri" : "";   # stringify | 
| 59 |  |  |  |  |  |  | # Get rid of potential wrapping | 
| 60 | 1216 |  |  |  |  | 2303 | $uri =~ s/^<(?:URL:)?(.*)>$/$1/;  # | 
| 61 | 1216 |  |  |  |  | 1796 | $uri =~ s/^"(.*)"$/$1/; | 
| 62 | 1216 |  |  |  |  | 2631 | $uri =~ s/^\s+//; | 
| 63 | 1216 |  |  |  |  | 2092 | $uri =~ s/\s+$//; | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 1216 |  |  |  |  | 1478 | my $impclass; | 
| 66 | 1216 | 100 |  |  |  | 4952 | if ($uri =~ m/^($scheme_re):/so) { | 
| 67 | 925 |  |  |  |  | 2121 | $scheme = $1; | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  | else { | 
| 70 | 291 | 100 | 66 |  |  | 1779 | if (($impclass = ref($scheme))) { | 
|  |  | 100 |  |  |  |  |  | 
| 71 | 11 |  |  |  |  | 53 | $scheme = $scheme->scheme; | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  | elsif ($scheme && $scheme =~ m/^($scheme_re)(?::|$)/o) { | 
| 74 | 136 |  |  |  |  | 377 | $scheme = $1; | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  | } | 
| 77 |  |  |  |  |  |  | $impclass ||= implementor($scheme) || | 
| 78 | 1216 |  | 66 |  |  | 3862 | do { | 
|  |  |  | 66 |  |  |  |  | 
| 79 |  |  |  |  |  |  | require URI::_foreign; | 
| 80 |  |  |  |  |  |  | $impclass = 'URI::_foreign'; | 
| 81 |  |  |  |  |  |  | }; | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 1216 |  |  |  |  | 3631 | return $impclass->_init($uri, $scheme); | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | sub new_abs | 
| 88 |  |  |  |  |  |  | { | 
| 89 | 1 |  |  | 1 | 1 | 460 | my($class, $uri, $base) = @_; | 
| 90 | 1 |  |  |  |  | 3 | $uri = $class->new($uri, $base); | 
| 91 | 1 |  |  |  |  | 3 | $uri->abs($base); | 
| 92 |  |  |  |  |  |  | } | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | sub _init | 
| 96 |  |  |  |  |  |  | { | 
| 97 | 1214 |  |  | 1214 |  | 2227 | my $class = shift; | 
| 98 | 1214 |  |  |  |  | 2173 | my($str, $scheme) = @_; | 
| 99 |  |  |  |  |  |  | # find all funny characters and encode the bytes. | 
| 100 | 1214 |  |  |  |  | 3084 | $str = $class->_uric_escape($str); | 
| 101 | 1214 | 50 | 66 |  |  | 5357 | $str = "$scheme:$str" unless $str =~ /^$scheme_re:/o || | 
| 102 |  |  |  |  |  |  | $class->_no_scheme_ok; | 
| 103 | 1214 |  |  |  |  | 2535 | my $self = bless \$str, $class; | 
| 104 | 1214 |  |  |  |  | 3629 | $self; | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  | #-- Version: 5.11+ | 
| 109 |  |  |  |  |  |  | #   Since the complete URI will be percent-encoded including '[' and ']', | 
| 110 |  |  |  |  |  |  | #   we selectively unescape square brackets from the authority/host part of the URI. | 
| 111 |  |  |  |  |  |  | #   Derived modules that implement _uric_escape() should take this into account | 
| 112 |  |  |  |  |  |  | #   if they do not rely on URI::_uric_escape(). | 
| 113 |  |  |  |  |  |  | #   No unescaping is performed for the userinfo@ part of the authority part. | 
| 114 |  |  |  |  |  |  | sub _fix_uric_escape_for_host_part { | 
| 115 | 1214 |  |  | 1214 |  | 1338 | return if HAS_RESERVED_SQUARE_BRACKETS; | 
| 116 | 1208 | 100 |  |  |  | 2767 | return if $_[0] !~ /%/; | 
| 117 | 75 | 100 |  |  |  | 808 | return if $_[0] =~ m{^(?:$URI::schemes_without_host_part_re):}os; | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | # until a scheme specific handler is available, fall back to previous behavior of v5.10 (i.e. 'mailto:') | 
| 120 | 71 | 100 |  |  |  | 383 | if ($_[0] =~ m{^(?:$URI::fallback_schemes_re):}os) { | 
| 121 | 10 |  |  |  |  | 30 | $_[0]    =~ s/\%5B/[/gi; | 
| 122 | 10 |  |  |  |  | 21 | $_[0]    =~ s/\%5D/]/gi; | 
| 123 | 10 |  |  |  |  | 15 | return; | 
| 124 |  |  |  |  |  |  | } | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 61 | 100 |  |  |  | 781 | if ($_[0] =~ m{^((?:$URI::scheme_re:)?)//([^/?\#]+)(.*)$}os) { | 
| 127 | 46 |  |  |  |  | 124 | my $orig          = $2; | 
| 128 | 46 |  |  |  |  | 285 | my ($user, $host) = $orig =~ /^(.*@)?([^@]*)$/; | 
| 129 | 46 |  | 100 |  |  | 217 | $user  ||= ''; | 
| 130 | 46 | 100 |  |  |  | 185 | my $port = $host =~ s/(:\d+)$// ? $1 : ''; | 
| 131 |  |  |  |  |  |  | #MAINT: die() here if scheme indicates TCP/UDP and port is out of range [0..65535] ? | 
| 132 | 46 |  |  |  |  | 235 | $host    =~ s/\%5B/[/gi; | 
| 133 | 46 |  |  |  |  | 123 | $host    =~ s/\%5D/]/gi; | 
| 134 | 46 |  |  |  |  | 746 | $_[0]    =~ s/\Q$orig\E/$user$host$port/; | 
| 135 |  |  |  |  |  |  | } | 
| 136 |  |  |  |  |  |  | } | 
| 137 |  |  |  |  |  |  |  | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | sub _uric_escape | 
| 140 |  |  |  |  |  |  | { | 
| 141 | 1214 |  |  | 1214 |  | 2069 | my($class, $str) = @_; | 
| 142 | 1214 |  |  |  |  | 3057 | $str =~ s*([^$uric\#])* URI::Escape::escape_char($1) *ego; | 
|  | 256 |  |  |  |  | 545 |  | 
| 143 | 1214 |  |  |  |  | 2473 | _fix_uric_escape_for_host_part( $str ); | 
| 144 | 1214 |  |  |  |  | 2692 | utf8::downgrade($str); | 
| 145 | 1214 |  |  |  |  | 2233 | return $str; | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | my %require_attempted; | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | sub implementor | 
| 151 |  |  |  |  |  |  | { | 
| 152 | 1205 |  |  | 1205 | 0 | 2212 | my($scheme, $impclass) = @_; | 
| 153 | 1205 | 100 | 66 |  |  | 5955 | if (!$scheme || $scheme !~ /\A$scheme_re\z/o) { | 
| 154 | 144 |  |  |  |  | 718 | require URI::_generic; | 
| 155 | 144 |  |  |  |  | 608 | return "URI::_generic"; | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 1061 |  |  |  |  | 2151 | $scheme = lc($scheme); | 
| 159 |  |  |  |  |  |  |  | 
| 160 | 1061 | 50 |  |  |  | 1821 | if ($impclass) { | 
| 161 |  |  |  |  |  |  | # Set the implementor class for a given scheme | 
| 162 | 0 |  |  |  |  | 0 | my $old = $implements{$scheme}; | 
| 163 | 0 |  |  |  |  | 0 | $impclass->_init_implementor($scheme); | 
| 164 | 0 |  |  |  |  | 0 | $implements{$scheme} = $impclass; | 
| 165 | 0 |  |  |  |  | 0 | return $old; | 
| 166 |  |  |  |  |  |  | } | 
| 167 |  |  |  |  |  |  |  | 
| 168 | 1061 |  |  |  |  | 1828 | my $ic = $implements{$scheme}; | 
| 169 | 1061 | 100 |  |  |  | 4113 | return $ic if $ic; | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | # scheme not yet known, look for internal or | 
| 172 |  |  |  |  |  |  | # preloaded (with 'use') implementation | 
| 173 | 107 |  |  |  |  | 214 | $ic = "URI::$scheme";  # default location | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | # turn scheme into a valid perl identifier by a simple transformation... | 
| 176 | 107 |  |  |  |  | 230 | $ic =~ s/\+/_P/g; | 
| 177 | 107 |  |  |  |  | 192 | $ic =~ s/\./_O/g; | 
| 178 | 107 |  |  |  |  | 189 | $ic =~ s/\-/_/g; | 
| 179 |  |  |  |  |  |  |  | 
| 180 | 41 |  |  | 41 |  | 43009 | no strict 'refs'; | 
|  | 41 |  |  |  |  | 119 |  | 
|  | 41 |  |  |  |  | 65265 |  | 
| 181 |  |  |  |  |  |  | # check we actually have one for the scheme: | 
| 182 | 107 | 100 |  |  |  | 143 | unless (@{"${ic}::ISA"}) { | 
|  | 107 |  |  |  |  | 795 |  | 
| 183 | 103 | 50 |  |  |  | 328 | if (not exists $require_attempted{$ic}) { | 
| 184 |  |  |  |  |  |  | # Try to load it | 
| 185 | 103 |  |  |  |  | 182 | my $_old_error = $@; | 
| 186 | 103 |  |  |  |  | 5223 | eval "require $ic"; | 
| 187 | 103 | 50 | 66 |  |  | 1165 | die $@ if $@ && $@ !~ /Can\'t locate.*in \@INC/; | 
| 188 | 103 |  |  |  |  | 300 | $@ = $_old_error; | 
| 189 |  |  |  |  |  |  | } | 
| 190 | 103 | 100 |  |  |  | 149 | return undef unless @{"${ic}::ISA"}; | 
|  | 103 |  |  |  |  | 615 |  | 
| 191 |  |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  |  | 
| 193 | 62 |  |  |  |  | 660 | $ic->_init_implementor($scheme); | 
| 194 | 62 |  |  |  |  | 175 | $implements{$scheme} = $ic; | 
| 195 | 62 |  |  |  |  | 350 | $ic; | 
| 196 |  |  |  |  |  |  | } | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | sub _init_implementor | 
| 200 |  |  |  |  |  |  | { | 
| 201 | 62 |  |  | 62 |  | 278 | my($class, $scheme) = @_; | 
| 202 |  |  |  |  |  |  | # Remember that one implementor class may actually | 
| 203 |  |  |  |  |  |  | # serve to implement several URI schemes. | 
| 204 |  |  |  |  |  |  | } | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | sub clone | 
| 208 |  |  |  |  |  |  | { | 
| 209 | 421 |  |  | 421 | 1 | 776 | my $self = shift; | 
| 210 | 421 |  |  |  |  | 742 | my $other = $$self; | 
| 211 | 421 |  |  |  |  | 992 | bless \$other, ref $self; | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  |  | 
| 214 | 0 |  |  | 0 | 0 | 0 | sub TO_JSON { ${$_[0]} } | 
|  | 0 |  |  |  |  | 0 |  | 
| 215 |  |  |  |  |  |  |  | 
| 216 | 0 |  |  | 0 |  | 0 | sub _no_scheme_ok { 0 } | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | sub _scheme | 
| 219 |  |  |  |  |  |  | { | 
| 220 | 1554 |  |  | 1554 |  | 1943 | my $self = shift; | 
| 221 |  |  |  |  |  |  |  | 
| 222 | 1554 | 100 |  |  |  | 2887 | unless (@_) { | 
| 223 | 1220 | 100 |  |  |  | 6798 | return undef unless $$self =~ /^($scheme_re):/o; | 
| 224 | 904 |  |  |  |  | 2859 | return $1; | 
| 225 |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  |  | 
| 227 | 334 |  |  |  |  | 418 | my $old; | 
| 228 | 334 |  |  |  |  | 496 | my $new = shift; | 
| 229 | 334 | 100 | 100 |  |  | 1158 | if (defined($new) && length($new)) { | 
| 230 | 270 | 50 |  |  |  | 1286 | Carp::croak("Bad scheme '$new'") unless $new =~ /^$scheme_re$/o; | 
| 231 | 270 | 100 |  |  |  | 1081 | $old = $1 if $$self =~ s/^($scheme_re)://o; | 
| 232 | 270 |  |  |  |  | 885 | my $newself = URI->new("$new:$$self"); | 
| 233 | 270 |  |  |  |  | 755 | $$self = $$newself; | 
| 234 | 270 |  |  |  |  | 627 | bless $self, ref($newself); | 
| 235 |  |  |  |  |  |  | } | 
| 236 |  |  |  |  |  |  | else { | 
| 237 | 64 | 50 |  |  |  | 194 | if ($self->_no_scheme_ok) { | 
| 238 | 64 | 50 |  |  |  | 592 | $old = $1 if $$self =~ s/^($scheme_re)://o; | 
| 239 | 64 | 50 | 33 |  |  | 234 | Carp::carp("Oops, opaque part now look like scheme") | 
| 240 |  |  |  |  |  |  | if $^W && $$self =~ m/^$scheme_re:/o | 
| 241 |  |  |  |  |  |  | } | 
| 242 |  |  |  |  |  |  | else { | 
| 243 | 0 | 0 |  |  |  | 0 | $old = $1 if $$self =~ m/^($scheme_re):/o; | 
| 244 |  |  |  |  |  |  | } | 
| 245 |  |  |  |  |  |  | } | 
| 246 |  |  |  |  |  |  |  | 
| 247 | 334 |  |  |  |  | 607 | return $old; | 
| 248 |  |  |  |  |  |  | } | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | sub scheme | 
| 251 |  |  |  |  |  |  | { | 
| 252 | 1085 |  |  | 1085 | 1 | 2198 | my $scheme = shift->_scheme(@_); | 
| 253 | 1085 | 100 |  |  |  | 2473 | return undef unless defined $scheme; | 
| 254 | 585 |  |  |  |  | 1835 | lc($scheme); | 
| 255 |  |  |  |  |  |  | } | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | sub has_recognized_scheme { | 
| 258 | 6 |  |  | 6 | 1 | 45 | my $self = shift; | 
| 259 | 6 |  |  |  |  | 39 | return ref($self) !~ /^URI::_(?:foreign|generic)\z/; | 
| 260 |  |  |  |  |  |  | } | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | sub opaque | 
| 263 |  |  |  |  |  |  | { | 
| 264 | 84 |  |  | 84 | 1 | 126 | my $self = shift; | 
| 265 |  |  |  |  |  |  |  | 
| 266 | 84 | 100 |  |  |  | 172 | unless (@_) { | 
| 267 | 57 | 50 |  |  |  | 688 | $$self =~ /^(?:$scheme_re:)?([^\#]*)/o or die; | 
| 268 | 57 |  |  |  |  | 305 | return $1; | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  |  | 
| 271 | 27 | 50 |  |  |  | 423 | $$self =~ /^($scheme_re:)?    # optional scheme | 
| 272 |  |  |  |  |  |  | ([^\#]*)          # opaque | 
| 273 |  |  |  |  |  |  | (\#.*)?           # optional fragment | 
| 274 |  |  |  |  |  |  | $/sx or die; | 
| 275 |  |  |  |  |  |  |  | 
| 276 | 27 |  |  |  |  | 80 | my $old_scheme = $1; | 
| 277 | 27 |  |  |  |  | 56 | my $old_opaque = $2; | 
| 278 | 27 |  |  |  |  | 46 | my $old_frag   = $3; | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 27 |  |  |  |  | 34 | my $new_opaque = shift; | 
| 281 | 27 | 100 |  |  |  | 50 | $new_opaque = "" unless defined $new_opaque; | 
| 282 | 27 |  |  |  |  | 216 | $new_opaque =~ s/([^$uric])/ URI::Escape::escape_char($1)/ego; | 
|  | 14 |  |  |  |  | 41 |  | 
| 283 | 27 |  |  |  |  | 73 | utf8::downgrade($new_opaque); | 
| 284 |  |  |  |  |  |  |  | 
| 285 | 27 | 100 |  |  |  | 63 | $$self = defined($old_scheme) ? $old_scheme : ""; | 
| 286 | 27 |  |  |  |  | 62 | $$self .= $new_opaque; | 
| 287 | 27 | 100 |  |  |  | 52 | $$self .= $old_frag if defined $old_frag; | 
| 288 |  |  |  |  |  |  |  | 
| 289 | 27 |  |  |  |  | 85 | $old_opaque; | 
| 290 |  |  |  |  |  |  | } | 
| 291 |  |  |  |  |  |  |  | 
| 292 | 1 |  |  | 1 | 1 | 12 | sub path { goto &opaque }  # alias | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  |  | 
| 295 |  |  |  |  |  |  | sub fragment | 
| 296 |  |  |  |  |  |  | { | 
| 297 | 71 |  |  | 71 | 1 | 131 | my $self = shift; | 
| 298 | 71 | 100 |  |  |  | 160 | unless (@_) { | 
| 299 | 51 | 100 |  |  |  | 267 | return undef unless $$self =~ /\#(.*)/s; | 
| 300 | 24 |  |  |  |  | 119 | return $1; | 
| 301 |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  |  | 
| 303 | 20 |  |  |  |  | 27 | my $old; | 
| 304 | 20 | 100 |  |  |  | 108 | $old = $1 if $$self =~ s/\#(.*)//s; | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 20 |  |  |  |  | 41 | my $new_frag = shift; | 
| 307 | 20 | 100 |  |  |  | 44 | if (defined $new_frag) { | 
| 308 | 18 |  |  |  |  | 131 | $new_frag =~ s/([^$uric])/ URI::Escape::escape_char($1) /ego; | 
|  | 2 |  |  |  |  | 7 |  | 
| 309 | 18 |  |  |  |  | 45 | utf8::downgrade($new_frag); | 
| 310 | 18 |  |  |  |  | 55 | $$self .= "#$new_frag"; | 
| 311 |  |  |  |  |  |  | } | 
| 312 | 20 |  |  |  |  | 40 | $old; | 
| 313 |  |  |  |  |  |  | } | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | sub as_string | 
| 317 |  |  |  |  |  |  | { | 
| 318 | 726 |  |  | 726 | 1 | 1917 | my $self = shift; | 
| 319 | 726 |  |  |  |  | 2976 | $$self; | 
| 320 |  |  |  |  |  |  | } | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | sub as_iri | 
| 324 |  |  |  |  |  |  | { | 
| 325 | 15 |  |  | 15 | 1 | 25 | my $self = shift; | 
| 326 | 15 |  |  |  |  | 26 | my $str = $$self; | 
| 327 | 15 | 100 |  |  |  | 77 | if ($str =~ s/%([89a-fA-F][0-9a-fA-F])/chr(hex($1))/eg) { | 
|  | 274 |  |  |  |  | 599 |  | 
| 328 |  |  |  |  |  |  | # All this crap because the more obvious: | 
| 329 |  |  |  |  |  |  | # | 
| 330 |  |  |  |  |  |  | #   Encode::decode("UTF-8", $str, sub { sprintf "%%%02X", shift }) | 
| 331 |  |  |  |  |  |  | # | 
| 332 |  |  |  |  |  |  | # doesn't work before Encode 2.39.  Wait for a standard release | 
| 333 |  |  |  |  |  |  | # to bundle that version. | 
| 334 |  |  |  |  |  |  |  | 
| 335 | 10 |  |  |  |  | 53 | require Encode; | 
| 336 | 10 |  |  |  |  | 27 | my $enc = Encode::find_encoding("UTF-8"); | 
| 337 | 10 |  |  |  |  | 303 | my $u = ""; | 
| 338 | 10 |  |  |  |  | 22 | while (length $str) { | 
| 339 | 13 |  |  |  |  | 75 | $u .= $enc->decode($str, Encode::FB_QUIET()); | 
| 340 | 13 | 100 |  |  |  | 108 | if (length $str) { | 
| 341 |  |  |  |  |  |  | # escape next char | 
| 342 | 3 |  |  |  |  | 21 | $u .= URI::Escape::escape_char(substr($str, 0, 1, "")); | 
| 343 |  |  |  |  |  |  | } | 
| 344 |  |  |  |  |  |  | } | 
| 345 | 10 |  |  |  |  | 19 | $str = $u; | 
| 346 |  |  |  |  |  |  | } | 
| 347 | 15 |  |  |  |  | 86 | return $str; | 
| 348 |  |  |  |  |  |  | } | 
| 349 |  |  |  |  |  |  |  | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | sub canonical | 
| 352 |  |  |  |  |  |  | { | 
| 353 |  |  |  |  |  |  | # Make sure scheme is lowercased, that we don't escape unreserved chars, | 
| 354 |  |  |  |  |  |  | # and that we use upcase escape sequences. | 
| 355 |  |  |  |  |  |  |  | 
| 356 | 458 |  |  | 458 | 1 | 615 | my $self = shift; | 
| 357 | 458 |  | 100 |  |  | 822 | my $scheme = $self->_scheme || ""; | 
| 358 | 458 |  |  |  |  | 912 | my $uc_scheme = $scheme =~ /[A-Z]/; | 
| 359 | 458 |  |  |  |  | 783 | my $esc = $$self =~ /%[a-fA-F0-9]{2}/; | 
| 360 | 458 | 100 | 100 |  |  | 1840 | return $self unless $uc_scheme || $esc; | 
| 361 |  |  |  |  |  |  |  | 
| 362 | 53 |  |  |  |  | 149 | my $other = $self->clone; | 
| 363 | 53 | 100 |  |  |  | 117 | if ($uc_scheme) { | 
| 364 | 10 |  |  |  |  | 29 | $other->_scheme(lc $scheme); | 
| 365 |  |  |  |  |  |  | } | 
| 366 | 53 | 100 |  |  |  | 110 | if ($esc) { | 
| 367 | 43 |  |  |  |  | 186 | $$other =~ s{%([0-9a-fA-F]{2})} | 
|  | 226 |  |  |  |  | 550 |  | 
| 368 | 226 | 100 |  |  |  | 935 | { my $a = chr(hex($1)); | 
| 369 |  |  |  |  |  |  | $a =~ /^[$unreserved]\z/o ? $a : "%\U$1" | 
| 370 |  |  |  |  |  |  | }ge; | 
| 371 | 53 |  |  |  |  | 176 | } | 
| 372 |  |  |  |  |  |  | return $other; | 
| 373 |  |  |  |  |  |  | } | 
| 374 |  |  |  |  |  |  |  | 
| 375 |  |  |  |  |  |  | # Compare two URIs, subclasses will provide a more correct implementation | 
| 376 | 15 |  |  | 15 | 1 | 69 | sub eq { | 
| 377 | 15 | 50 |  |  |  | 40 | my($self, $other) = @_; | 
| 378 | 15 | 100 |  |  |  | 45 | $self  = URI->new($self, $other) unless ref $self; | 
| 379 | 15 | 50 |  |  |  | 63 | $other = URI->new($other, $self) unless ref $other; | 
| 380 |  |  |  |  |  |  | ref($self) eq ref($other) &&                # same class | 
| 381 |  |  |  |  |  |  | $self->canonical->as_string eq $other->canonical->as_string; | 
| 382 |  |  |  |  |  |  | } | 
| 383 |  |  |  |  |  |  |  | 
| 384 | 1 |  |  | 1 | 1 | 4 | # generic-URI transformation methods | 
| 385 | 1 |  |  | 1 | 1 | 5 | sub abs { $_[0]; } | 
| 386 |  |  |  |  |  |  | sub rel { $_[0]; } | 
| 387 | 4 |  |  | 4 | 1 | 18 |  | 
| 388 |  |  |  |  |  |  | sub secure { 0 } | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | # help out Storable | 
| 391 | 0 |  |  | 0 | 0 |  | sub STORABLE_freeze { | 
| 392 | 0 |  |  |  |  |  | my($self, $cloning) = @_; | 
| 393 |  |  |  |  |  |  | return $$self; | 
| 394 |  |  |  |  |  |  | } | 
| 395 |  |  |  |  |  |  |  | 
| 396 | 0 |  |  | 0 | 0 |  | sub STORABLE_thaw { | 
| 397 | 0 |  |  |  |  |  | my($self, $cloning, $str) = @_; | 
| 398 |  |  |  |  |  |  | $$self = $str; | 
| 399 |  |  |  |  |  |  | } | 
| 400 |  |  |  |  |  |  |  | 
| 401 |  |  |  |  |  |  | 1; | 
| 402 |  |  |  |  |  |  |  | 
| 403 |  |  |  |  |  |  | __END__ |