| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package URI; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 40 |  |  | 40 |  | 2145835 | use strict; | 
|  | 40 |  |  |  |  | 372 |  | 
|  | 40 |  |  |  |  | 1185 |  | 
| 4 | 40 |  |  | 40 |  | 196 | use warnings; | 
|  | 40 |  |  |  |  | 115 |  | 
|  | 40 |  |  |  |  | 3258 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | our $VERSION = '5.19'; | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | # 1=version 5.10 and earlier; 0=version 5.11 and later | 
| 9 | 40 | 100 |  | 40 |  | 261 | use constant HAS_RESERVED_SQUARE_BRACKETS => $ENV{URI_HAS_RESERVED_SQUARE_BRACKETS} ? 1 : 0; | 
|  | 40 |  |  |  |  | 82 |  | 
|  | 40 |  |  |  |  | 11907 |  | 
| 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 | 40 |  |  | 40 |  | 288 | use Carp (); | 
|  | 40 |  |  |  |  | 77 |  | 
|  | 40 |  |  |  |  | 879 |  | 
| 41 | 40 |  |  | 40 |  | 17242 | use URI::Escape (); | 
|  | 40 |  |  |  |  | 107 |  | 
|  | 40 |  |  |  |  | 4259 |  | 
| 42 |  |  |  |  |  |  |  | 
| 43 | 845 |  |  | 845 |  | 53146 | use overload ('""'     => sub { ${$_[0]} }, | 
|  | 845 |  |  |  |  | 4165 |  | 
| 44 | 31 |  |  | 31 |  | 154 | '=='     => sub { _obj_eq(@_) }, | 
| 45 | 1 |  |  | 1 |  | 1082 | '!='     => sub { !_obj_eq(@_) }, | 
| 46 | 40 |  |  |  |  | 438 | fallback => 1, | 
| 47 | 40 |  |  | 40 |  | 49072 | ); | 
|  | 40 |  |  |  |  | 42190 |  | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | # Check if two objects are the same object | 
| 50 |  |  |  |  |  |  | sub _obj_eq { | 
| 51 | 32 |  |  | 32 |  | 128 | return overload::StrVal($_[0]) eq overload::StrVal($_[1]); | 
| 52 |  |  |  |  |  |  | } | 
| 53 |  |  |  |  |  |  |  | 
| 54 |  |  |  |  |  |  | sub new | 
| 55 |  |  |  |  |  |  | { | 
| 56 | 1213 |  |  | 1213 | 1 | 70639 | my($class, $uri, $scheme) = @_; | 
| 57 |  |  |  |  |  |  |  | 
| 58 | 1213 | 50 |  |  |  | 3175 | $uri = defined ($uri) ? "$uri" : "";   # stringify | 
| 59 |  |  |  |  |  |  | # Get rid of potential wrapping | 
| 60 | 1213 |  |  |  |  | 2323 | $uri =~ s/^<(?:URL:)?(.*)>$/$1/;  # | 
| 61 | 1213 |  |  |  |  | 1668 | $uri =~ s/^"(.*)"$/$1/; | 
| 62 | 1213 |  |  |  |  | 2738 | $uri =~ s/^\s+//; | 
| 63 | 1213 |  |  |  |  | 2123 | $uri =~ s/\s+$//; | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 1213 |  |  |  |  | 1466 | my $impclass; | 
| 66 | 1213 | 100 |  |  |  | 5071 | if ($uri =~ m/^($scheme_re):/so) { | 
| 67 | 922 |  |  |  |  | 2106 | $scheme = $1; | 
| 68 |  |  |  |  |  |  | } | 
| 69 |  |  |  |  |  |  | else { | 
| 70 | 291 | 100 | 66 |  |  | 1890 | if (($impclass = ref($scheme))) { | 
|  |  | 100 |  |  |  |  |  | 
| 71 | 11 |  |  |  |  | 50 | $scheme = $scheme->scheme; | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  | elsif ($scheme && $scheme =~ m/^($scheme_re)(?::|$)/o) { | 
| 74 | 136 |  |  |  |  | 383 | $scheme = $1; | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  | } | 
| 77 |  |  |  |  |  |  | $impclass ||= implementor($scheme) || | 
| 78 | 1213 |  | 66 |  |  | 4065 | do { | 
|  |  |  | 66 |  |  |  |  | 
| 79 |  |  |  |  |  |  | require URI::_foreign; | 
| 80 |  |  |  |  |  |  | $impclass = 'URI::_foreign'; | 
| 81 |  |  |  |  |  |  | }; | 
| 82 |  |  |  |  |  |  |  | 
| 83 | 1213 |  |  |  |  | 3533 | return $impclass->_init($uri, $scheme); | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | sub new_abs | 
| 88 |  |  |  |  |  |  | { | 
| 89 | 1 |  |  | 1 | 1 | 402 | my($class, $uri, $base) = @_; | 
| 90 | 1 |  |  |  |  | 4 | $uri = $class->new($uri, $base); | 
| 91 | 1 |  |  |  |  | 8 | $uri->abs($base); | 
| 92 |  |  |  |  |  |  | } | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | sub _init | 
| 96 |  |  |  |  |  |  | { | 
| 97 | 1211 |  |  | 1211 |  | 1888 | my $class = shift; | 
| 98 | 1211 |  |  |  |  | 2151 | my($str, $scheme) = @_; | 
| 99 |  |  |  |  |  |  | # find all funny characters and encode the bytes. | 
| 100 | 1211 |  |  |  |  | 3031 | $str = $class->_uric_escape($str); | 
| 101 | 1211 | 50 | 66 |  |  | 5349 | $str = "$scheme:$str" unless $str =~ /^$scheme_re:/o || | 
| 102 |  |  |  |  |  |  | $class->_no_scheme_ok; | 
| 103 | 1211 |  |  |  |  | 2554 | my $self = bless \$str, $class; | 
| 104 | 1211 |  |  |  |  | 3905 | $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 | 1211 |  |  | 1211 |  | 1439 | return if HAS_RESERVED_SQUARE_BRACKETS; | 
| 116 | 1205 | 100 |  |  |  | 3057 | return if $_[0] !~ /%/; | 
| 117 | 73 | 100 |  |  |  | 719 | 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 | 69 | 100 |  |  |  | 466 | if ($_[0] =~ m{^(?:$URI::fallback_schemes_re):}os) { | 
| 121 | 10 |  |  |  |  | 26 | $_[0]    =~ s/\%5B/[/gi; | 
| 122 | 10 |  |  |  |  | 23 | $_[0]    =~ s/\%5D/]/gi; | 
| 123 | 10 |  |  |  |  | 16 | return; | 
| 124 |  |  |  |  |  |  | } | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 59 | 100 |  |  |  | 765 | if ($_[0] =~ m{^((?:$URI::scheme_re:)?)//([^/?\#]+)(.*)$}os) { | 
| 127 | 44 |  |  |  |  | 148 | my $orig          = $2; | 
| 128 | 44 |  |  |  |  | 276 | my ($user, $host) = $orig =~ /^(.*@)?([^@]*)$/; | 
| 129 | 44 |  | 100 |  |  | 204 | $user  ||= ''; | 
| 130 | 44 | 100 |  |  |  | 190 | my $port = $host =~ s/(:\d+)$// ? $1 : ''; | 
| 131 |  |  |  |  |  |  | #MAINT: die() here if scheme indicates TCP/UDP and port is out of range [0..65535] ? | 
| 132 | 44 |  |  |  |  | 190 | $host    =~ s/\%5B/[/gi; | 
| 133 | 44 |  |  |  |  | 126 | $host    =~ s/\%5D/]/gi; | 
| 134 | 44 |  |  |  |  | 701 | $_[0]    =~ s/\Q$orig\E/$user$host$port/; | 
| 135 |  |  |  |  |  |  | } | 
| 136 |  |  |  |  |  |  | } | 
| 137 |  |  |  |  |  |  |  | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | sub _uric_escape | 
| 140 |  |  |  |  |  |  | { | 
| 141 | 1211 |  |  | 1211 |  | 2130 | my($class, $str) = @_; | 
| 142 | 1211 |  |  |  |  | 3105 | $str =~ s*([^$uric\#])* URI::Escape::escape_char($1) *ego; | 
|  | 255 |  |  |  |  | 505 |  | 
| 143 | 1211 |  |  |  |  | 2462 | _fix_uric_escape_for_host_part( $str ); | 
| 144 | 1211 |  |  |  |  | 2662 | utf8::downgrade($str); | 
| 145 | 1211 |  |  |  |  | 2284 | return $str; | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | my %require_attempted; | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | sub implementor | 
| 151 |  |  |  |  |  |  | { | 
| 152 | 1202 |  |  | 1202 | 0 | 2194 | my($scheme, $impclass) = @_; | 
| 153 | 1202 | 100 | 66 |  |  | 6022 | if (!$scheme || $scheme !~ /\A$scheme_re\z/o) { | 
| 154 | 144 |  |  |  |  | 716 | require URI::_generic; | 
| 155 | 144 |  |  |  |  | 591 | return "URI::_generic"; | 
| 156 |  |  |  |  |  |  | } | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 1058 |  |  |  |  | 2252 | $scheme = lc($scheme); | 
| 159 |  |  |  |  |  |  |  | 
| 160 | 1058 | 50 |  |  |  | 1781 | 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 | 1058 |  |  |  |  | 1843 | my $ic = $implements{$scheme}; | 
| 169 | 1058 | 100 |  |  |  | 3991 | return $ic if $ic; | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | # scheme not yet known, look for internal or | 
| 172 |  |  |  |  |  |  | # preloaded (with 'use') implementation | 
| 173 | 105 |  |  |  |  | 216 | $ic = "URI::$scheme";  # default location | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | # turn scheme into a valid perl identifier by a simple transformation... | 
| 176 | 105 |  |  |  |  | 239 | $ic =~ s/\+/_P/g; | 
| 177 | 105 |  |  |  |  | 178 | $ic =~ s/\./_O/g; | 
| 178 | 105 |  |  |  |  | 175 | $ic =~ s/\-/_/g; | 
| 179 |  |  |  |  |  |  |  | 
| 180 | 40 |  |  | 40 |  | 42421 | no strict 'refs'; | 
|  | 40 |  |  |  |  | 145 |  | 
|  | 40 |  |  |  |  | 63516 |  | 
| 181 |  |  |  |  |  |  | # check we actually have one for the scheme: | 
| 182 | 105 | 100 |  |  |  | 147 | unless (@{"${ic}::ISA"}) { | 
|  | 105 |  |  |  |  | 5051 |  | 
| 183 | 101 | 50 |  |  |  | 333 | if (not exists $require_attempted{$ic}) { | 
| 184 |  |  |  |  |  |  | # Try to load it | 
| 185 | 101 |  |  |  |  | 181 | my $_old_error = $@; | 
| 186 | 101 |  |  |  |  | 5264 | eval "require $ic"; | 
| 187 | 101 | 50 | 66 |  |  | 1173 | die $@ if $@ && $@ !~ /Can\'t locate.*in \@INC/; | 
| 188 | 101 |  |  |  |  | 341 | $@ = $_old_error; | 
| 189 |  |  |  |  |  |  | } | 
| 190 | 101 | 100 |  |  |  | 160 | return undef unless @{"${ic}::ISA"}; | 
|  | 101 |  |  |  |  | 654 |  | 
| 191 |  |  |  |  |  |  | } | 
| 192 |  |  |  |  |  |  |  | 
| 193 | 60 |  |  |  |  | 669 | $ic->_init_implementor($scheme); | 
| 194 | 60 |  |  |  |  | 187 | $implements{$scheme} = $ic; | 
| 195 | 60 |  |  |  |  | 349 | $ic; | 
| 196 |  |  |  |  |  |  | } | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | sub _init_implementor | 
| 200 |  |  |  |  |  |  | { | 
| 201 | 60 |  |  | 60 |  | 270 | 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 | 420 |  |  | 420 | 1 | 821 | my $self = shift; | 
| 210 | 420 |  |  |  |  | 699 | my $other = $$self; | 
| 211 | 420 |  |  |  |  | 990 | 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 | 1552 |  |  | 1552 |  | 1923 | my $self = shift; | 
| 221 |  |  |  |  |  |  |  | 
| 222 | 1552 | 100 |  |  |  | 2871 | unless (@_) { | 
| 223 | 1219 | 100 |  |  |  | 6432 | return undef unless $$self =~ /^($scheme_re):/o; | 
| 224 | 903 |  |  |  |  | 2865 | return $1; | 
| 225 |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  |  | 
| 227 | 333 |  |  |  |  | 415 | my $old; | 
| 228 | 333 |  |  |  |  | 483 | my $new = shift; | 
| 229 | 333 | 100 | 100 |  |  | 1217 | if (defined($new) && length($new)) { | 
| 230 | 269 | 50 |  |  |  | 1306 | Carp::croak("Bad scheme '$new'") unless $new =~ /^$scheme_re$/o; | 
| 231 | 269 | 100 |  |  |  | 1141 | $old = $1 if $$self =~ s/^($scheme_re)://o; | 
| 232 | 269 |  |  |  |  | 902 | my $newself = URI->new("$new:$$self"); | 
| 233 | 269 |  |  |  |  | 698 | $$self = $$newself; | 
| 234 | 269 |  |  |  |  | 599 | bless $self, ref($newself); | 
| 235 |  |  |  |  |  |  | } | 
| 236 |  |  |  |  |  |  | else { | 
| 237 | 64 | 50 |  |  |  | 185 | if ($self->_no_scheme_ok) { | 
| 238 | 64 | 50 |  |  |  | 541 | $old = $1 if $$self =~ s/^($scheme_re)://o; | 
| 239 | 64 | 50 | 33 |  |  | 233 | 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 | 333 |  |  |  |  | 587 | return $old; | 
| 248 |  |  |  |  |  |  | } | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | sub scheme | 
| 251 |  |  |  |  |  |  | { | 
| 252 | 1084 |  |  | 1084 | 1 | 2100 | my $scheme = shift->_scheme(@_); | 
| 253 | 1084 | 100 |  |  |  | 2558 | return undef unless defined $scheme; | 
| 254 | 584 |  |  |  |  | 1533 | lc($scheme); | 
| 255 |  |  |  |  |  |  | } | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | sub has_recognized_scheme { | 
| 258 | 5 |  |  | 5 | 1 | 37 | my $self = shift; | 
| 259 | 5 |  |  |  |  | 35 | return ref($self) !~ /^URI::_(?:foreign|generic)\z/; | 
| 260 |  |  |  |  |  |  | } | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | sub opaque | 
| 263 |  |  |  |  |  |  | { | 
| 264 | 84 |  |  | 84 | 1 | 128 | my $self = shift; | 
| 265 |  |  |  |  |  |  |  | 
| 266 | 84 | 100 |  |  |  | 179 | unless (@_) { | 
| 267 | 57 | 50 |  |  |  | 706 | $$self =~ /^(?:$scheme_re:)?([^\#]*)/o or die; | 
| 268 | 57 |  |  |  |  | 336 | return $1; | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  |  | 
| 271 | 27 | 50 |  |  |  | 400 | $$self =~ /^($scheme_re:)?    # optional scheme | 
| 272 |  |  |  |  |  |  | ([^\#]*)          # opaque | 
| 273 |  |  |  |  |  |  | (\#.*)?           # optional fragment | 
| 274 |  |  |  |  |  |  | $/sx or die; | 
| 275 |  |  |  |  |  |  |  | 
| 276 | 27 |  |  |  |  | 66 | my $old_scheme = $1; | 
| 277 | 27 |  |  |  |  | 59 | my $old_opaque = $2; | 
| 278 | 27 |  |  |  |  | 49 | my $old_frag   = $3; | 
| 279 |  |  |  |  |  |  |  | 
| 280 | 27 |  |  |  |  | 39 | my $new_opaque = shift; | 
| 281 | 27 | 100 |  |  |  | 52 | $new_opaque = "" unless defined $new_opaque; | 
| 282 | 27 |  |  |  |  | 221 | $new_opaque =~ s/([^$uric])/ URI::Escape::escape_char($1)/ego; | 
|  | 14 |  |  |  |  | 38 |  | 
| 283 | 27 |  |  |  |  | 71 | utf8::downgrade($new_opaque); | 
| 284 |  |  |  |  |  |  |  | 
| 285 | 27 | 100 |  |  |  | 62 | $$self = defined($old_scheme) ? $old_scheme : ""; | 
| 286 | 27 |  |  |  |  | 70 | $$self .= $new_opaque; | 
| 287 | 27 | 100 |  |  |  | 58 | $$self .= $old_frag if defined $old_frag; | 
| 288 |  |  |  |  |  |  |  | 
| 289 | 27 |  |  |  |  | 73 | $old_opaque; | 
| 290 |  |  |  |  |  |  | } | 
| 291 |  |  |  |  |  |  |  | 
| 292 | 1 |  |  | 1 | 1 | 17 | sub path { goto &opaque }  # alias | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  |  | 
| 295 |  |  |  |  |  |  | sub fragment | 
| 296 |  |  |  |  |  |  | { | 
| 297 | 71 |  |  | 71 | 1 | 126 | my $self = shift; | 
| 298 | 71 | 100 |  |  |  | 150 | unless (@_) { | 
| 299 | 51 | 100 |  |  |  | 248 | return undef unless $$self =~ /\#(.*)/s; | 
| 300 | 24 |  |  |  |  | 140 | return $1; | 
| 301 |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  |  | 
| 303 | 20 |  |  |  |  | 28 | my $old; | 
| 304 | 20 | 100 |  |  |  | 92 | $old = $1 if $$self =~ s/\#(.*)//s; | 
| 305 |  |  |  |  |  |  |  | 
| 306 | 20 |  |  |  |  | 34 | my $new_frag = shift; | 
| 307 | 20 | 100 |  |  |  | 44 | if (defined $new_frag) { | 
| 308 | 18 |  |  |  |  | 159 | $new_frag =~ s/([^$uric])/ URI::Escape::escape_char($1) /ego; | 
|  | 2 |  |  |  |  | 6 |  | 
| 309 | 18 |  |  |  |  | 48 | utf8::downgrade($new_frag); | 
| 310 | 18 |  |  |  |  | 48 | $$self .= "#$new_frag"; | 
| 311 |  |  |  |  |  |  | } | 
| 312 | 20 |  |  |  |  | 40 | $old; | 
| 313 |  |  |  |  |  |  | } | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | sub as_string | 
| 317 |  |  |  |  |  |  | { | 
| 318 | 726 |  |  | 726 | 1 | 2391 | my $self = shift; | 
| 319 | 726 |  |  |  |  | 3062 | $$self; | 
| 320 |  |  |  |  |  |  | } | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | sub as_iri | 
| 324 |  |  |  |  |  |  | { | 
| 325 | 15 |  |  | 15 | 1 | 22 | my $self = shift; | 
| 326 | 15 |  |  |  |  | 25 | my $str = $$self; | 
| 327 | 15 | 100 |  |  |  | 74 | if ($str =~ s/%([89a-fA-F][0-9a-fA-F])/chr(hex($1))/eg) { | 
|  | 274 |  |  |  |  | 636 |  | 
| 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 |  |  |  |  | 54 | require Encode; | 
| 336 | 10 |  |  |  |  | 30 | my $enc = Encode::find_encoding("UTF-8"); | 
| 337 | 10 |  |  |  |  | 307 | my $u = ""; | 
| 338 | 10 |  |  |  |  | 26 | while (length $str) { | 
| 339 | 13 |  |  |  |  | 67 | $u .= $enc->decode($str, Encode::FB_QUIET()); | 
| 340 | 13 | 100 |  |  |  | 101 | if (length $str) { | 
| 341 |  |  |  |  |  |  | # escape next char | 
| 342 | 3 |  |  |  |  | 17 | $u .= URI::Escape::escape_char(substr($str, 0, 1, "")); | 
| 343 |  |  |  |  |  |  | } | 
| 344 |  |  |  |  |  |  | } | 
| 345 | 10 |  |  |  |  | 20 | $str = $u; | 
| 346 |  |  |  |  |  |  | } | 
| 347 | 15 |  |  |  |  | 40 | 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 | 457 |  |  | 457 | 1 | 612 | my $self = shift; | 
| 357 | 457 |  | 100 |  |  | 951 | my $scheme = $self->_scheme || ""; | 
| 358 | 457 |  |  |  |  | 957 | my $uc_scheme = $scheme =~ /[A-Z]/; | 
| 359 | 457 |  |  |  |  | 824 | my $esc = $$self =~ /%[a-fA-F0-9]{2}/; | 
| 360 | 457 | 100 | 100 |  |  | 1967 | return $self unless $uc_scheme || $esc; | 
| 361 |  |  |  |  |  |  |  | 
| 362 | 52 |  |  |  |  | 147 | my $other = $self->clone; | 
| 363 | 52 | 100 |  |  |  | 124 | if ($uc_scheme) { | 
| 364 | 10 |  |  |  |  | 30 | $other->_scheme(lc $scheme); | 
| 365 |  |  |  |  |  |  | } | 
| 366 | 52 | 100 |  |  |  | 115 | if ($esc) { | 
| 367 | 42 |  |  |  |  | 188 | $$other =~ s{%([0-9a-fA-F]{2})} | 
|  | 189 |  |  |  |  | 407 |  | 
| 368 | 189 | 100 |  |  |  | 806 | { my $a = chr(hex($1)); | 
| 369 |  |  |  |  |  |  | $a =~ /^[$unreserved]\z/o ? $a : "%\U$1" | 
| 370 |  |  |  |  |  |  | }ge; | 
| 371 | 52 |  |  |  |  | 153 | } | 
| 372 |  |  |  |  |  |  | return $other; | 
| 373 |  |  |  |  |  |  | } | 
| 374 |  |  |  |  |  |  |  | 
| 375 |  |  |  |  |  |  | # Compare two URIs, subclasses will provide a more correct implementation | 
| 376 | 15 |  |  | 15 | 1 | 40 | sub eq { | 
| 377 | 15 | 50 |  |  |  | 38 | my($self, $other) = @_; | 
| 378 | 15 | 100 |  |  |  | 45 | $self  = URI->new($self, $other) unless ref $self; | 
| 379 | 15 | 50 |  |  |  | 65 | $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 | 8 | # generic-URI transformation methods | 
| 385 | 1 |  |  | 1 | 1 | 5 | sub abs { $_[0]; } | 
| 386 |  |  |  |  |  |  | sub rel { $_[0]; } | 
| 387 | 3 |  |  | 3 | 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__ |