diff --git .htaccess .htaccess
index e78c440..6c507f2 100644
--- .htaccess
+++ .htaccess
@@ -88,11 +88,10 @@ DirectoryIndex index.php index.html index.htm
   # uncomment the following line:
   # RewriteBase /
 
-  # Rewrite URLs of the form 'x' to the form 'index.php?q=x'.
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteCond %{REQUEST_URI} !=/favicon.ico
-  RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
+  RewriteRule ^ index.php [L]
 </IfModule>
 
 # $Id: .htaccess,v 1.104 2009-08-16 12:10:36 dries Exp $
diff --git includes/bootstrap.inc includes/bootstrap.inc
index c265610..b33e189 100644
--- includes/bootstrap.inc
+++ includes/bootstrap.inc
@@ -469,6 +469,20 @@ function drupal_environment_initialize() {
     $_SERVER['HTTP_HOST'] = '';
   }
 
+  // When clean URLs are enabled, emulate ?q=foo/bar using REQUEST_URI. It is
+  // not possible to append the query string using mod_rewrite without the B
+  // flag (this was added in Apache 2.2.8), because mod_rewrite unescapes the
+  // path before passing it on to PHP.
+  if (!isset($_GET['q']) && isset($_SERVER['REQUEST_URI'])) {
+    $request_path = $_SERVER['REQUEST_URI'];
+    $query_pos = strpos($_SERVER['REQUEST_URI'], '?');
+    if ($query_pos !== FALSE) {
+      $request_path = substr($request_path, 0, $query_pos);
+    }
+    $base_path_len = strlen(trim(dirname($_SERVER['SCRIPT_NAME']), '\,/'));
+    $_GET['q'] = substr(urldecode($request_path), $base_path_len + 2);
+  }
+
   // Enforce E_ALL, but allow users to set levels not part of E_ALL.
   error_reporting(E_ALL | error_reporting());
 
diff --git includes/common.inc includes/common.inc
index 9f45fec..ed85377 100644
--- includes/common.inc
+++ includes/common.inc
@@ -2236,7 +2236,7 @@ function url($path = NULL, array $options = array()) {
 
   $base = $options['absolute'] ? $options['base_url'] . '/' : base_path();
   $prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix'];
-  $path = drupal_encode_path($prefix . $path);
+  $path = drupal_urlencode($prefix . $path);
 
   if (variable_get('clean_url', '0')) {
     // With Clean URLs.
@@ -3529,35 +3529,19 @@ function drupal_json($var = NULL) {
 }
 
 /**
- * Wrapper around urlencode() which avoids Apache quirks.
+ * Wrapper around rawurlencode().
+ *
+ * For aesthetic reasons slashes are not escaped.
  *
  * Should be used when placing arbitrary data in an URL. Note that Drupal paths
  * are urlencoded() when passed through url() and do not require urlencoding()
  * of individual components.
  *
- * Notes:
- * - For esthetic reasons, we do not escape slashes. This also avoids a 'feature'
- *   in Apache where it 404s on any path containing '%2F'.
- * - mod_rewrite unescapes %-encoded ampersands, hashes, and slashes when clean
- *   URLs are used, which are interpreted as delimiters by PHP. These
- *   characters are double escaped so PHP will still see the encoded version.
- * - With clean URLs, Apache changes '//' to '/', so every second slash is
- *   double escaped.
- * - This function should only be used on paths, not on query string arguments,
- *   otherwise unwanted double encoding will occur.
- *
  * @param $text
  *   String to encode
  */
-function drupal_encode_path($text) {
-  if (variable_get('clean_url', '0')) {
-    return str_replace(array('%2F', '%26', '%23', '//'),
-                        array('/', '%2526', '%2523', '/%252F'),
-                        rawurlencode($text));
-  }
-  else {
-    return str_replace('%2F', '/', rawurlencode($text));
-  }
+function drupal_urlencode($text) {
+  return str_replace('%2F', '/', rawurlencode($text));
 }
 
 /**
diff --git misc/autocomplete.js misc/autocomplete.js
index 4e24a0e..eb007f8 100644
--- misc/autocomplete.js
+++ misc/autocomplete.js
@@ -275,7 +275,7 @@ Drupal.ACDB.prototype.search = function (searchString) {
     // Ajax GET request for autocompletion.
     $.ajax({
       type: 'GET',
-      url: db.uri + '/' + Drupal.encodePath(searchString),
+      url: db.uri + '/' + Drupal.encodeURIComponent(searchString),
       dataType: 'json',
       success: function (matches) {
         if (typeof matches.status == 'undefined' || matches.status != 0) {
diff --git misc/drupal.js misc/drupal.js
index f3a7d2b..6a9dc1e 100644
--- misc/drupal.js
+++ misc/drupal.js
@@ -267,14 +267,13 @@ Drupal.unfreezeHeight = function () {
 };
 
 /**
- * Wrapper around encodeURIComponent() which avoids Apache quirks (equivalent of
- * drupal_encode_path() in PHP). This function should only be used on paths, not
- * on query string arguments.
+ * Wrapper around encodeURIComponent().
+ *
+ * For aesthetic reasons slashes are not escaped.
  */
-Drupal.encodePath = function (item, uri) {
+Drupal.encodeURIComponent = function (item, uri) {
   uri = uri || location.href;
-  item = encodeURIComponent(item).replace(/%2F/g, '/');
-  return (uri.indexOf('?q=') != -1) ? item : item.replace(/%26/g, '%2526').replace(/%23/g, '%2523').replace(/\/\//g, '/%252F');
+  return encodeURIComponent(item).replace(/%2F/g, '/');
 };
 
 /**
