Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1011
diff -u -p -r1.1011 common.inc
--- includes/common.inc	9 Oct 2009 16:33:13 -0000	1.1011
+++ includes/common.inc	10 Oct 2009 23:39:04 -0000
@@ -486,7 +486,11 @@ function drupal_get_destination() {
 }
 
 /**
- * Wrapper around parse_url() to parse a given URL into an associative array, suitable for url().
+ * Wrapper around parse_url() to parse a system URL string into an associative array, suitable for url().
+ *
+ * This function should only be used for URLs that have been generated by the
+ * system, resp. url(). It should not be used for URLs that come from external
+ * sources, or URLs that link to external resources.
  *
  * The returned array contains a 'path' that may be passed separately to url().
  * For example:
@@ -552,6 +556,13 @@ function drupal_parse_url($url) {
       $options['fragment'] = $parts['fragment'];
     }
   }
+  // The 'q' parameter contains the path of the current page if clean URLs are
+  // disabled. It overrides the 'path' of the URL when present, even if clean
+  // URLs are enabled, due to how Apache rewriting rules work.
+  if (isset($options['query']['q'])) {
+    $options['path'] = $options['query']['q'];
+    unset($options['query']['q']);
+  }
 
   return $options;
 }
Index: modules/simpletest/tests/common.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v
retrieving revision 1.82
diff -u -p -r1.82 common.test
--- modules/simpletest/tests/common.test	9 Oct 2009 08:08:56 -0000	1.82
+++ modules/simpletest/tests/common.test	10 Oct 2009 23:34:47 -0000
@@ -120,6 +120,24 @@ class CommonURLUnitTest extends DrupalUn
       'fragment' => 'foo',
     );
     $this->assertEqual(drupal_parse_url($url), $result, t('External URL parsed correctly.'));
+
+    // Verify proper parsing of URLs when clean URLs are disabled.
+    // Non-clean URLs #1: Absolute URL generated by url().
+    $url = $GLOBALS['base_url'] . '/?q=foo/bar&bar=baz#foo';
+    $result = array(
+      'path' => 'foo/bar',
+      'query' => array('bar' => 'baz'),
+      'fragment' => 'foo',
+    );
+    $this->assertEqual(drupal_parse_url($url), $result, t('Absolute URL with clean URLs disabled parsed correctly.'));
+
+    // Non-clean URLs #2: Relative URL generated by url().
+    $url = '?q=foo/bar&bar=baz#foo';
+    $this->assertEqual(drupal_parse_url($url), $result, t('Relative URL with clean URLs disabled parsed correctly.'));
+
+    // Non-clean URLs #3: URL generated by url() on non-Apache webserver.
+    $url = 'index.php?q=foo/bar&bar=baz#foo';
+    $this->assertEqual(drupal_parse_url($url), $result, t('Relative URL on non-Apache webserver with clean URLs disabled parsed correctly.'));
   }
 
   /**
