Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
5.7 KiB

  1. package URI::_generic;
  2. require URI;
  3. require URI::_query;
  4. @ISA=qw(URI URI::_query);
  5. use strict;
  6. use URI::Escape qw(uri_unescape);
  7. use Carp ();
  8. my $ACHAR = $URI::uric; $ACHAR =~ s,\\[/?],,g;
  9. my $PCHAR = $URI::uric; $PCHAR =~ s,\\[?],,g;
  10. sub _no_scheme_ok { 1 }
  11. sub authority
  12. {
  13. my $self = shift;
  14. $$self =~ m,^((?:$URI::scheme_re:)?)(?://([^/?\#]*))?(.*)$,os or die;
  15. if (@_) {
  16. my $auth = shift;
  17. $$self = $1;
  18. my $rest = $3;
  19. if (defined $auth) {
  20. $auth =~ s/([^$ACHAR])/$URI::Escape::escapes{$1}/go;
  21. $$self .= "//$auth";
  22. }
  23. _check_path($rest, $$self);
  24. $$self .= $rest;
  25. }
  26. $2;
  27. }
  28. sub path
  29. {
  30. my $self = shift;
  31. $$self =~ m,^((?:[^:/?\#]+:)?(?://[^/?\#]*)?)([^?\#]*)(.*)$,s or die;
  32. if (@_) {
  33. $$self = $1;
  34. my $rest = $3;
  35. my $new_path = shift;
  36. $new_path = "" unless defined $new_path;
  37. $new_path =~ s/([^$PCHAR])/$URI::Escape::escapes{$1}/go;
  38. _check_path($new_path, $$self);
  39. $$self .= $new_path . $rest;
  40. }
  41. $2;
  42. }
  43. sub path_query
  44. {
  45. my $self = shift;
  46. $$self =~ m,^((?:[^:/?\#]+:)?(?://[^/?\#]*)?)([^\#]*)(.*)$,s or die;
  47. if (@_) {
  48. $$self = $1;
  49. my $rest = $3;
  50. my $new_path = shift;
  51. $new_path = "" unless defined $new_path;
  52. $new_path =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go;
  53. _check_path($new_path, $$self);
  54. $$self .= $new_path . $rest;
  55. }
  56. $2;
  57. }
  58. sub _check_path
  59. {
  60. my($path, $pre) = @_;
  61. my $prefix;
  62. if ($pre =~ m,/,) { # authority present
  63. $prefix = "/" if length($path) && $path !~ m,^[/?\#],;
  64. } else {
  65. if ($path =~ m,^//,) {
  66. Carp::carp("Path starting with double slash is confusing")
  67. if $^W;
  68. } elsif (!length($pre) && $path =~ m,^[^:/?\#]+:,) {
  69. Carp::carp("Path might look like scheme, './' prepended")
  70. if $^W;
  71. $prefix = "./";
  72. }
  73. }
  74. substr($_[0], 0, 0) = $prefix if defined $prefix;
  75. }
  76. sub path_segments
  77. {
  78. my $self = shift;
  79. my $path = $self->path;
  80. if (@_) {
  81. my @arg = @_; # make a copy
  82. for (@arg) {
  83. if (ref($_)) {
  84. my @seg = @$_;
  85. $seg[0] =~ s/%/%25/g;
  86. for (@seg) { s/;/%3B/g; }
  87. $_ = join(";", @seg);
  88. } else {
  89. s/%/%25/g; s/;/%3B/g;
  90. }
  91. s,/,%2F,g;
  92. }
  93. $self->path(join("/", @arg));
  94. }
  95. return $path unless wantarray;
  96. map {/;/ ? $self->_split_segment($_)
  97. : uri_unescape($_) }
  98. split('/', $path, -1);
  99. }
  100. sub _split_segment
  101. {
  102. my $self = shift;
  103. require URI::_segment;
  104. URI::_segment->new(@_);
  105. }
  106. sub abs
  107. {
  108. my $self = shift;
  109. my $base = shift || Carp::croak("Missing base argument");
  110. if (my $scheme = $self->scheme) {
  111. return $self unless $URI::ABS_ALLOW_RELATIVE_SCHEME;
  112. $base = URI->new($base) unless ref $base;
  113. return $self unless $scheme eq $base->scheme;
  114. }
  115. $base = URI->new($base) unless ref $base;
  116. my $abs = $self->clone;
  117. $abs->scheme($base->scheme);
  118. return $abs if $$self =~ m,^(?:$URI::scheme_re:)?//,o;
  119. $abs->authority($base->authority);
  120. my $path = $self->path;
  121. return $abs if $path =~ m,^/,;
  122. if (!length($path) && !defined($self->query)) {
  123. my $abs = $base->clone;
  124. $abs->fragment($self->fragment);
  125. return $abs;
  126. }
  127. my $p = $base->path;
  128. $p =~ s,[^/]+$,,;
  129. $p .= $path;
  130. my @p = split('/', $p, -1);
  131. shift(@p) if @p && !length($p[0]);
  132. my $i = 1;
  133. while ($i < @p) {
  134. #print "$i ", join("/", @p), " ($p[$i])\n";
  135. if ($p[$i-1] eq ".") {
  136. splice(@p, $i-1, 1);
  137. $i-- if $i > 1;
  138. } elsif ($p[$i] eq ".." && $p[$i-1] ne "..") {
  139. splice(@p, $i-1, 2);
  140. if ($i > 1) {
  141. $i--;
  142. push(@p, "") if $i == @p;
  143. }
  144. } else {
  145. $i++;
  146. }
  147. }
  148. $p[-1] = "" if @p && $p[-1] eq "."; # trailing "/."
  149. if ($URI::ABS_REMOTE_LEADING_DOTS) {
  150. shift @p while @p && $p[0] =~ /^\.\.?$/;
  151. }
  152. $abs->path("/" . join("/", @p));
  153. $abs;
  154. }
  155. # The oposite of $url->abs. Return a URI which is as relative as possible
  156. sub rel {
  157. my $self = shift;
  158. my $base = shift || Carp::croak("Missing base argument");
  159. my $rel = $self->clone;
  160. $base = URI->new($base) unless ref $base;
  161. #my($scheme, $auth, $path) = @{$rel}{qw(scheme authority path)};
  162. my $scheme = $rel->scheme;
  163. my $auth = $rel->authority;
  164. my $path = $rel->path;
  165. if (!defined($scheme) && !defined($auth)) {
  166. # it is already relative
  167. return $rel;
  168. }
  169. #my($bscheme, $bauth, $bpath) = @{$base}{qw(scheme authority path)};
  170. my $bscheme = $base->scheme;
  171. my $bauth = $base->authority;
  172. my $bpath = $base->path;
  173. for ($bscheme, $bauth, $auth) {
  174. $_ = '' unless defined
  175. }
  176. unless ($scheme eq $bscheme && $auth eq $bauth) {
  177. # different location, can't make it relative
  178. return $rel;
  179. }
  180. for ($path, $bpath) { $_ = "/$_" unless m,^/,; }
  181. # Make it relative by eliminating scheme and authority
  182. $rel->scheme(undef);
  183. $rel->authority(undef);
  184. # This loop is based on code from Nicolai Langfeldt <[email protected]>.
  185. # First we calculate common initial path components length ($li).
  186. my $li = 1;
  187. while (1) {
  188. my $i = index($path, '/', $li);
  189. last if $i < 0 ||
  190. $i != index($bpath, '/', $li) ||
  191. substr($path,$li,$i-$li) ne substr($bpath,$li,$i-$li);
  192. $li=$i+1;
  193. }
  194. # then we nuke it from both paths
  195. substr($path, 0,$li) = '';
  196. substr($bpath,0,$li) = '';
  197. if ($path eq $bpath &&
  198. defined($rel->fragment) &&
  199. !defined($rel->query)) {
  200. $rel->path("");
  201. } else {
  202. # Add one "../" for each path component left in the base path
  203. $path = ('../' x $bpath =~ tr|/|/|) . $path;
  204. $path = "./" if $path eq "";
  205. $rel->path($path);
  206. }
  207. $rel;
  208. }
  209. 1;