📄 _generic.pm
字号:
my $old = $self->{'path'};
$old = '' unless defined $old;
$old = "/$old" if $old !~ m|^/| && defined $self->{'netloc'};
if (@_) {
$self->_elem('path',
join("/", map {uri_escape($_, $URI::URL::reserved)} @_));
}
map { uri_unescape($_) } split("/", $old, -1);
}
sub eparams { shift->_elem('params', @_); }
sub params {
my $self = shift;
my $old = $self->_elem('params', map {uri_escape($_,$URI::URL::reserved_no_form)} @_);
return uri_unescape($old) if defined $old;
undef;
}
sub equery { shift->_elem('query', @_); }
sub query {
my $self = shift;
my $old = $self->_elem('query', map { uri_escape($_, $URI::URL::reserved_no_form) } @_);
if (defined(wantarray) && defined($old)) {
if ($old =~ /%(?:26|2[bB]|3[dD])/) { # contains escaped '=' '&' or '+'
my $mess;
for ($old) {
$mess = "Query contains both '+' and '%2B'"
if /\+/ && /%2[bB]/;
$mess = "Form query contains escaped '=' or '&'"
if /=/ && /%(?:3[dD]|26)/;
}
if ($mess) {
Carp::croak("$mess (you must call equery)");
}
}
# Now it should be safe to unescape the string without loosing
# information
return uri_unescape($old);
}
undef;
}
# No efrag method because the fragment is always stored unescaped
sub frag { shift->_elem('frag', @_); }
sub crack
{
my $self = shift;
return $self unless wantarray;
my @c = @{$self}{qw(scheme user password host port path params query frag)};
if (!$c[0]) {
# try to determine scheme
my $base = $self->base;
$c[0] = $base->scheme if $base;
$c[0] ||= 'http'; # last resort, default in URI::URL::new
}
$c[4] ||= $self->default_port;
@c;
}
# Generic-RL: Resolving Relative URL into an Absolute URL
#
# Based on RFC1808 section 4
#
sub abs
{
my($self, $base, $allow_relative_scheme) = @_;
$allow_relative_scheme = $URI::URL::ABS_ALLOW_RELATIVE_SCHEME if @_ < 3;
my $embed = $self->clone;
$base = $self->base unless $base; # default to default base
return $embed unless $base; # we have no base (step1)
$base = new URI::URL $base unless ref $base; # make obj if needed
my($scheme, $host, $path, $params, $query, $frag) =
@{$embed}{qw(scheme host path params query frag)};
# just use base if we are empty (2a)
return $base->clone
unless grep(defined($_) && $_ ne '',
$scheme,$host,$port,$path,$params,$query,$frag);
# if we have a scheme we must already be absolute (2b),
#
# but sec. 5.2 also says: Some older parsers allow the scheme name
# to be present in a relative URL if it is the same as the base
# URL scheme. This is considered to be a loophole in prior
# specifications of the partial URLs and should be avoided by
# future parsers.
#
# The old behavoir can be enabled by passing a TRUE value to the
# $allow_relative_scheme parameter.
return $embed if $scheme &&
(!$allow_relative_scheme || $scheme ne $base->{'scheme'});
$embed->{'_str'} = ''; # void cached string
$embed->{'scheme'} = $base->{'scheme'}; # (2c)
return $embed if $embed->{'netloc'}; # (3)
$embed->netloc($base->{'netloc'}); # (3)
return $embed if $path =~ m:^/:; # (4)
if ($path eq '') { # (5)
$embed->{'path'} = $base->{'path'}; # (5)
return $embed if defined $embed->{'params'}; # (5a)
$embed->{'params'} = $base->{'params'}; # (5a)
return $embed if defined $embed->{'query'}; # (5b)
$embed->{'query'} = $base->{'query'}; # (5b)
return $embed;
}
# (Step 6) # draft 6 suggests stack based approach
my $basepath = $base->{'path'};
my $relpath = $embed->{'path'};
$basepath =~ s!^/!!;
$basepath =~ s!/$!/.!; # prevent empty segment
my @path = split('/', $basepath); # base path into segments
pop(@path); # remove last segment
$relpath =~ s!/$!/.!; # prevent empty segment
push(@path, split('/', $relpath)); # append relative segments
my @newpath = ();
my $isdir = 0;
my $segment;
foreach $segment (@path) { # left to right
if ($segment eq '.') { # ignore "same" directory
$isdir = 1;
}
elsif ($segment eq '..') {
$isdir = 1;
my $last = pop(@newpath);
if (!defined $last) { # nothing to pop
push(@newpath, $segment); # so must append
}
elsif ($last eq '..') { # '..' cannot match '..'
# so put back again, and append
push(@newpath, $last, $segment);
}
#else
# it was a component,
# keep popped
} else {
$isdir = 0;
push(@newpath, $segment);
}
}
if ($URI::URL::ABS_REMOTE_LEADING_DOTS) {
shift @newpath while @newpath && $newpath[0] =~ /^\.\.?$/;
}
$embed->{'path'} = '/' . join('/', @newpath) .
($isdir && @newpath ? '/' : '');
$embed;
}
# The oposite of $url->abs. Return a URL as much relative as possible
sub rel {
my($self, $base) = @_;
my $rel = $self->clone;
$base = $self->base unless $base;
return $rel unless $base;
$base = new URI::URL $base unless ref $base;
$rel->base($base);
my($scheme, $netloc, $path) = @{$rel}{qw(scheme netloc path)};
if (!defined($scheme) && !defined($netloc)) {
# it is already relative
return $rel;
}
my($bscheme, $bnetloc, $bpath) = @{$base}{qw(scheme netloc path)};
for ($bscheme, $bnetloc, $netloc) { $_ = '' unless defined }
unless ($scheme eq $bscheme && $netloc eq $bnetloc) {
# different location, can't make it relative
return $rel;
}
for ($path, $bpath) { $_ = "/$_" unless m,^/,; }
# Make it relative by eliminating scheme and netloc
$rel->{'scheme'} = undef;
$rel->netloc(undef);
# This loop is based on code from Nicolai Langfeldt <janl@ifi.uio.no>.
# First we calculate common initial path components length ($li).
my $li = 1;
while (1) {
my $i = index($path, '/', $li);
last if $i < 0 ||
$i != index($bpath, '/', $li) ||
substr($path,$li,$i-$li) ne substr($bpath,$li,$i-$li);
$li=$i+1;
}
# then we nuke it from both paths
substr($path, 0,$li) = '';
substr($bpath,0,$li) = '';
if ($path eq $bpath && defined($rel->frag) && !defined($rel->equery)) {
$rel->epath('');
} else {
# Add one "../" for each path component left in the base path
$path = ('../' x $bpath =~ tr|/|/|) . $path;
$path = "./" if $path eq "";
$rel->epath($path);
}
$rel;
}
# Compare two URLs
sub eq {
my($self, $other) = @_;
local($^W) = 0; # avoid warnings if we compare undef values
$other = URI::URL->new($other, $self) unless ref $other;
# Compare scheme and netloc
return 0 if ref($self) ne ref($other); # must be same class
return 0 if $self->scheme ne $other->scheme; # Always lower case
return 0 if lc($self->netloc) ne lc($other->netloc); # Case-insensitive
# Compare full_path:
# According to <draft-ietf-http-v11-spec-05>:
# Characters other than those in the "reserved" and "unsafe" sets
# are equivalent to their %XX encodings.
my $fp1 = $self->full_path;
my $fp2 = $other->full_path;
for ($fp1, $fp2) {
s,%([\dA-Fa-f]{2}),
my $x = $1;
my $c = chr(hex($x));
$c =~ /^[;\/?:\@&=+\"\#%<>\0-\040\177]/ ? "%\L$x" : $c;
,eg;
}
return 0 if $fp1 ne $fp2;
return 0 if $self->frag ne $other->frag;
1;
}
1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -