4 @ISA=qw(URI URI::_query);
7 use URI::Escape qw(uri_unescape);
10 my $ACHAR = $URI::uric; $ACHAR =~ s,\\[/?],,g;
11 my $PCHAR = $URI::uric; $PCHAR =~ s,\\[?],,g;
13 sub _no_scheme_ok { 1 }
18 $$self =~ m,^((?:$URI::scheme_re:)?)(?://([^/?\#]*))?(.*)$,os or die;
25 $auth =~ s/([^$ACHAR])/ URI::Escape::escape_char($1)/ego;
28 _check_path($rest, $$self);
37 $$self =~ m,^((?:[^:/?\#]+:)?(?://[^/?\#]*)?)([^?\#]*)(.*)$,s or die;
43 $new_path = "" unless defined $new_path;
44 $new_path =~ s/([^$PCHAR])/ URI::Escape::escape_char($1)/ego;
45 _check_path($new_path, $$self);
46 $$self .= $new_path . $rest;
54 $$self =~ m,^((?:[^:/?\#]+:)?(?://[^/?\#]*)?)([^\#]*)(.*)$,s or die;
60 $new_path = "" unless defined $new_path;
61 $new_path =~ s/([^$URI::uric])/ URI::Escape::escape_char($1)/ego;
62 _check_path($new_path, $$self);
63 $$self .= $new_path . $rest;
72 if ($pre =~ m,/,) { # authority present
73 $prefix = "/" if length($path) && $path !~ m,^[/?\#],;
76 if ($path =~ m,^//,) {
77 Carp::carp("Path starting with double slash is confusing")
80 elsif (!length($pre) && $path =~ m,^[^:/?\#]+:,) {
81 Carp::carp("Path might look like scheme, './' prepended")
86 substr($_[0], 0, 0) = $prefix if defined $prefix;
92 my $path = $self->path;
94 my @arg = @_; # make a copy
99 for (@seg) { s/;/%3B/g; }
100 $_ = join(";", @seg);
103 s/%/%25/g; s/;/%3B/g;
107 $self->path(join("/", @arg));
109 return $path unless wantarray;
110 map {/;/ ? $self->_split_segment($_)
112 split('/', $path, -1);
119 require URI::_segment;
120 URI::_segment->new(@_);
127 my $base = shift || Carp::croak("Missing base argument");
129 if (my $scheme = $self->scheme) {
130 return $self unless $URI::ABS_ALLOW_RELATIVE_SCHEME;
131 $base = URI->new($base) unless ref $base;
132 return $self unless $scheme eq $base->scheme;
135 $base = URI->new($base) unless ref $base;
136 my $abs = $self->clone;
137 $abs->scheme($base->scheme);
138 return $abs if $$self =~ m,^(?:$URI::scheme_re:)?//,o;
139 $abs->authority($base->authority);
141 my $path = $self->path;
142 return $abs if $path =~ m,^/,;
144 if (!length($path)) {
145 my $abs = $base->clone;
146 my $query = $self->query;
147 $abs->query($query) if defined $query;
148 $abs->fragment($self->fragment);
155 my @p = split('/', $p, -1);
156 shift(@p) if @p && !length($p[0]);
159 #print "$i ", join("/", @p), " ($p[$i])\n";
160 if ($p[$i-1] eq ".") {
164 elsif ($p[$i] eq ".." && $p[$i-1] ne "..") {
168 push(@p, "") if $i == @p;
175 $p[-1] = "" if @p && $p[-1] eq "."; # trailing "/."
176 if ($URI::ABS_REMOTE_LEADING_DOTS) {
177 shift @p while @p && $p[0] =~ /^\.\.?$/;
179 $abs->path("/" . join("/", @p));
183 # The oposite of $url->abs. Return a URI which is as relative as possible
186 my $base = shift || Carp::croak("Missing base argument");
187 my $rel = $self->clone;
188 $base = URI->new($base) unless ref $base;
190 #my($scheme, $auth, $path) = @{$rel}{qw(scheme authority path)};
191 my $scheme = $rel->scheme;
192 my $auth = $rel->canonical->authority;
193 my $path = $rel->path;
195 if (!defined($scheme) && !defined($auth)) {
196 # it is already relative
200 #my($bscheme, $bauth, $bpath) = @{$base}{qw(scheme authority path)};
201 my $bscheme = $base->scheme;
202 my $bauth = $base->canonical->authority;
203 my $bpath = $base->path;
205 for ($bscheme, $bauth, $auth) {
206 $_ = '' unless defined
209 unless ($scheme eq $bscheme && $auth eq $bauth) {
210 # different location, can't make it relative
214 for ($path, $bpath) { $_ = "/$_" unless m,^/,; }
216 # Make it relative by eliminating scheme and authority
218 $rel->authority(undef);
220 # This loop is based on code from Nicolai Langfeldt <janl@ifi.uio.no>.
221 # First we calculate common initial path components length ($li).
224 my $i = index($path, '/', $li);
226 $i != index($bpath, '/', $li) ||
227 substr($path,$li,$i-$li) ne substr($bpath,$li,$i-$li);
230 # then we nuke it from both paths
231 substr($path, 0,$li) = '';
232 substr($bpath,0,$li) = '';
234 if ($path eq $bpath &&
235 defined($rel->fragment) &&
236 !defined($rel->query)) {
240 # Add one "../" for each path component left in the base path
241 $path = ('../' x $bpath =~ tr|/|/|) . $path;
242 $path = "./" if $path eq "";