Index: linkchecker.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/linkchecker/linkchecker.module,v
retrieving revision 1.7.2.138
diff -u -r1.7.2.138 linkchecker.module
--- linkchecker.module	16 Jan 2010 13:18:55 -0000	1.7.2.138
+++ linkchecker.module	27 Jun 2010 10:21:39 -0000
@@ -1020,21 +1020,7 @@
       }
       // Relative URLs like "./foo/bar" and "../foo/bar".
       elseif (!empty($absolute_content_path) && preg_match('!^\.{1,2}/!', $url)) {
-        $path = $absolute_content_path . $url;
-
-        // Remove './' segments where possible.
-        $path = str_replace('/./', '/', $path);
-
-        // Remove '../' segments where possible. Loop until all segments are removed.
-        // Taken over from _drupal_build_css_path() in common.inc.
-        $last = '';
-        while ($path != $last) {
-          $last = $path;
-          $path = preg_replace('`(^|/)(?!\.\./)([^/]+)/\.\./`', '$1', $path);
-        }
-
-        // Add URLs to array.
-        $links[] = $path;
+        $links[] = $absolute_content_path . $url;
       }
       // Relative URLs like "test.png".
       elseif (!empty($absolute_content_path) && preg_match('!^[^/]!', $url)) {
@@ -1252,7 +1238,7 @@
   $path = isset($uri['path']) ? $uri['path'] : '/';
 
   // Glue the URL variables.
-  $absolute_url = $scheme . $user . $host . $path;
+  $absolute_url = $scheme . $user . $host . _linkchecker_uri_normalization_remove_dot_segments($path);
 
   // Find the last slash and remove all after the last slash to get the path.
   $last_slash = strrpos($absolute_url, '/');
@@ -1262,6 +1248,37 @@
 }
 
 /**
+ * Remove "/./" and "/../" from a path as described in RFC 3986, section 5.2.4.
+ * See http://tools.ietf.org/html/rfc3986#section-5.2.4.
+ *
+ * @param $path
+ *   A string containing a path.
+ * @return
+ *   A string containing a normalized path.
+ */
+function _linkchecker_uri_normalization_remove_dot_segments($path) {
+  // Normalize path separator.
+  $path = strtr($path, '\\', '/');
+
+  // Handle "/./" - look for "." seperated by "/" or string boundary.
+  $path = preg_replace('@(?<=^|/)\.(?=/|$)@', '/', $path, -1);
+
+  do {
+    // Handle "//"
+    $path = preg_replace('@/{2,}@', '/', $path);
+    // Handle "/../" - look for "foo/.." seperated by "/" or string boundary,
+    // where "foo" is any string not containing "/" except "..".
+    $path = preg_replace('@(?<=^|/)(?!\.\.)[^/]+/\.\.(?=/|$)@', '/', $path, -1, $i);
+  }
+  while ($i > 0);
+
+  // Strip leading "/../".
+  $path = preg_replace('@(<?=^|/)\.\.(?=/|$)@', '', $path);
+
+  return $path;
+}
+
+/**
  * Verifies against the url blacklist, if the link status should be checked or not.
  */
 function _linkchecker_link_check_status_filter($url) {
