Index: modules/filter/filter.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v
retrieving revision 1.319
diff -u -p -r1.319 filter.module
--- modules/filter/filter.module	6 Mar 2010 06:39:00 -0000	1.319
+++ modules/filter/filter.module	6 Mar 2010 16:27:18 -0000
@@ -1157,8 +1157,16 @@ function _filter_url($text, $filter) {
 
   $text = ' ' . $text . ' ';
 
+  // Prepare allowed protocols for absolute URLs.
+  // @see filter_xss_bad_protocol()
+  $protocols = variable_get('filter_allowed_protocols', array('ftp', 'http', 'https', 'irc', 'mailto', 'news', 'nntp', 'rtsp', 'sftp', 'ssh', 'telnet', 'webcal'));
+  foreach ($protocols as $key => $value) {
+    $protocols[$key] .= ':';
+  }
+  $protocols = implode('|', $protocols);
+
   // Match absolute URLs.
-  $text = preg_replace_callback("`(<p>|<li>|<br\s*/?>|[ \n\r\t\(])((http://|https://|ftp://|mailto:|smb://|afp://|file://|gopher://|news://|ssl://|sslv2://|sslv3://|tls://|tcp://|udp://)([a-zA-Z0-9@:%_+*~#?&=.,/;-]*[a-zA-Z0-9@:%_+*~#&=/;-]))([.,?!]*?)(?=(</p>|</li>|<br\s*/?>|[ \n\r\t\)]))`i", '_filter_url_parse_full_links', $text);
+  $text = preg_replace_callback("`(<p>|<li>|<br\s*/?>|[ \n\r\t\(])(({$protocols})([a-zA-Z0-9@:%_+*~#?&=.,/;-]*[a-zA-Z0-9@:%_+*~#&=/;-]))([.,?!]*?)(?=(</p>|</li>|<br\s*/?>|[ \n\r\t\)]))`i", '_filter_url_parse_full_links', $text);
 
   // Match e-mail addresses.
   $text = preg_replace("`(<p>|<li>|<br\s*/?>|[ \n\r\t\(])([A-Za-z0-9._-]+@[A-Za-z0-9._+-]+\.[A-Za-z]{2,4})([.,?!]*?)(?=(</p>|</li>|<br\s*/?>|[ \n\r\t\)]))`i", '\1<a href="mailto:\2">\2</a>\3', $text);
Index: modules/filter/filter.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.test,v
retrieving revision 1.60
diff -u -p -r1.60 filter.test
--- modules/filter/filter.test	6 Mar 2010 06:39:00 -0000	1.60
+++ modules/filter/filter.test	6 Mar 2010 16:27:02 -0000
@@ -922,8 +922,21 @@ class FilterUnitTestCase extends DrupalU
     $f = _filter_url('http://www.example.com/?a=1&b=2', $filter);
     $this->assertEqual($f, '<a href="http://www.example.com/?a=1&amp;b=2" title="http://www.example.com/?a=1&amp;b=2">http://www.example.com/?a=1&amp;b=2</a>', t('Converting URLs -- ampersands.'));
 
-    $f = _filter_url('ftp://user:pass@ftp.example.com/dir1/dir2', $filter);
-    $this->assertEqual($f, '<a href="ftp://user:pass@ftp.example.com/dir1/dir2" title="ftp://user:pass@ftp.example.com/dir1/dir2">ftp://user:pass@ftp.example.com/dir1/dir2</a>', t('Converting URLs -- FTP scheme.'));
+    // Absolute URLs using different protocols and authentication.
+    $protocols = variable_get('filter_allowed_protocols', array('ftp', 'http', 'https', 'irc', 'mailto', 'news', 'nntp', 'rtsp', 'sftp', 'ssh', 'telnet', 'webcal'));
+    foreach ($protocols as $protocol) {
+      $vars = array('@protocol' => $protocol);
+      $url = strtr('@protocol://user:pass@@protocol.example.com/dir1/dir2', $vars);
+      $vars['@url'] = $url;
+      $result = _filter_url($url, $filter);
+      $expected = strtr('<a href="@url" title="@url">@url</a>', $vars);
+      $this->assertEqual($result, $expected, strtr('URL using @protocol:// properly converted.', $vars));
+    }
+
+    // Verify that a disallowed protocol is not converted.
+    $url = 'foo://www.example.com/bar';
+    $result = _filter_url($url, $filter);
+    $this->assertEqual($result, $url, 'URL using disallowed foo:// protocol not converted.');
 
     // Converting domain names.
     $f = _filter_url('www.example.com', $filter);
