Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.771
diff -u -p -r1.771 common.inc
--- includes/common.inc	9 Jun 2008 08:11:44 -0000	1.771
+++ includes/common.inc	10 Jun 2008 13:12:55 -0000
@@ -836,12 +836,16 @@ function valid_email_address($mail) {
  *   TRUE if the URL is in a valid format.
  */
 function valid_url($url, $absolute = FALSE) {
-  $allowed_characters = '[a-z0-9\/:_\-_\.\?\$,;~=#&%\+]';
+  $scheme = '[a-z0-9]+:\/\/';
+  $domain = '(?:[a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])';
+  $domain .= '(?:\.' . $domain . ')+';
+  $allowed_characters = '[a-z0-9\/:_\-_\.\?\$,;~=#&%\+\[\]]';
+
   if ($absolute) {
-    return preg_match("/^(http|https|ftp):\/\/" . $allowed_characters . "+$/i", $url);
+    return (bool)preg_match('/^' . $scheme . $domain . $allowed_characters . '+$/i', $url);
   }
   else {
-    return preg_match("/^" . $allowed_characters . "+$/i", $url);
+    return (bool)preg_match('/^(' . $scheme . '){0}' . $domain . $allowed_characters . '+$/i', $url);
   }
 }
 
Index: includes/common.test
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.test,v
retrieving revision 1.1
diff -u -p -r1.1 common.test
--- includes/common.test	9 Jun 2008 08:11:44 -0000	1.1
+++ includes/common.test	10 Jun 2008 13:12:55 -0000
@@ -52,3 +52,50 @@ class CommonFormatSizeTestCase extends D
     }
   }
 }
+
+class CommonValidURLTestCase extends DrupalWebTestCase {
+
+  /**
+   * Implementation of getInfo().
+   */
+  function getInfo() {
+    return array(
+      'name' => t('Common URL validator test'),
+      'description' => t('Check predefined URI\'s for validity.'),
+      'group' => t('System')
+    );
+  }
+
+  /**
+   * Implementation of setUp().
+   */
+  function setUp() {
+    $this->uris = array( // 'uri' => array((bool)<absolute>, '<test>');
+      'http://example.com'    => array('absolute' => TRUE, 'test' => 'assertTrue'),
+      'HTTP://ExAmPlE.CoM'    => array('absolute' => TRUE, 'test' => 'assertTrue'),
+      'http://example.com:81' => array('absolute' => TRUE, 'test' => 'assertTrue'),
+      'http://example.com/a'  => array('absolute' => TRUE, 'test' => 'assertTrue'),
+      'unknown://example.com' => array('absolute' => TRUE, 'test' => 'assertTrue'),
+      'ed2k://example.com'    => array('absolute' => TRUE, 'test' => 'assertTrue'),
+      'http://ÊxÃmPlʒ.com'    => array('absolute' => TRUE, 'test' => 'assertFalse'),
+      'ed-2k://example.com'   => array('absolute' => TRUE, 'test' => 'assertFalse'),
+      'example-foo'           => array('absolute' => TRUE, 'test' => 'assertFalse'),
+      'example.com/'          => array('absolute' => FALSE, 'test' => 'assertTrue'),
+      'http://ex-ample.com'   => array('absolute' => FALSE, 'test' => 'assertFalse'),
+      'example-bar'           => array('absolute' => FALSE, 'test' => 'assertFalse'),
+      'http://example.com:81/~user?var=value&var2[]=value#id' => array('absolute' => TRUE, 'test' => 'assertTrue'),
+      'example.com:81/~user?var=value&var2[]=value#id'        => array('absolute' => FALSE, 'test' => 'assertTrue'),
+    );
+    parent::setUp();
+  }
+ 
+  function testCommonValidUrl() {
+    foreach ($this->uris as $uri => $attributes) {
+      $absolute = ($attributes['absolute']) ? 'absolute' : 'relative';
+      $this->$attributes['test'](
+        valid_url($uri, $attributes['absolute']),
+        'Testing ' . $absolute . ' url: \'' . $uri . '\' for validity. %s'
+      );
+    }
+  }
+}
