diff -Naurw webform_old/includes/webform.pages.inc webform/includes/webform.pages.inc
--- webform_old/includes/webform.pages.inc	2013-08-19 15:51:00.000000000 +0100
+++ webform/includes/webform.pages.inc	2013-08-19 15:42:18.000000000 +0100
@@ -264,7 +264,7 @@
     if (empty($redirect_url)) {
       form_error($form['submission']['redirection']['redirect_url'], t('A valid URL is required for custom redirection.'));
     }
-    elseif (strpos($redirect_url, 'http') === 0 && !valid_url($redirect_url, TRUE)) {
+    elseif (strpos($redirect_url, 'http') === 0 && !valid_url(_webform_filter_url($redirect_url, TRUE))) {
       form_error($form['submission']['redirection']['redirect_url'], t('The entered URL is not a valid address.'));
     }
     else {
diff -Naurw webform_old/webform.module webform/webform.module
--- webform_old/webform.module	2013-08-19 15:51:00.000000000 +0100
+++ webform/webform.module	2013-08-19 15:49:46.000000000 +0100
@@ -2527,7 +2527,7 @@
 
   // Clean up the redirect URL and filter it for webform tokens.
   $redirect_url = trim($node->webform['redirect_url']);
-  $redirect_url = _webform_filter_values($redirect_url, $node, $submission, NULL, FALSE, TRUE);
+  $redirect_url = _webform_filter_url($redirect_url, $node, $submission);
 
 
   // Remove the domain name from the redirect.
@@ -2576,6 +2576,89 @@
 }
 
 /**
+ * Do token replacement and url encoding for redirect urls
+ * @param string $redirect_url
+ *   The URL to redirect to as entered by the
+ * @param $node
+ *   The full webform node
+ * @param $submission
+ *   The webform submission values
+ * @return string
+ *   The parsed and url encoded URL
+ */
+function _webform_filter_url($redirect_url, $node = NULL, $submission = NULL) {
+  $parsed_redirect_url = parse_url($redirect_url);
+  if (!empty($parsed_redirect_url['query']) && !empty($parsed_redirect_url['path'])) {
+    // If what the user has entered vaguely resembles a correct URL before token
+    // replacement, we separately handle the query string and the other components
+    foreach ($parsed_redirect_url as $key => $urlval) {
+      if($key != 'query') {
+        $parsed_redirect_url[$key] = _webform_filter_values($urlval, $node, $submission, NULL, FALSE, TRUE, FALSE);
+      }
+    }
+    // The query string has all tokens urlencoded
+    if (!empty($parsed_redirect_url['query'])) {
+      $matches = array();
+      // Filter out all tokens individually, pass them to _webform_filter_values
+      // for replacement, urlencode the result, and put back into the query string
+      if (preg_match_all('/\%[A-Za-z0-9:_\-]+(\[[A-Za-z0-9:_\-]*\])*/', $parsed_redirect_url['query'], $matches, PREG_SET_ORDER)) {
+        foreach ($matches as $match) {
+          $find = $match[0];
+          $replace = urlencode(_webform_filter_values($match[0], $node, $submission, NULL, FALSE, TRUE));
+          $parsed_redirect_url['query'] = str_replace($find, $replace, $parsed_redirect_url['query']);
+        }
+      }
+    }
+    $url = _webform_assemble_parsed_url($parsed_redirect_url);
+    // If the URL is valid, return it
+    if (valid_url($url, TRUE)) {
+      return $url;
+    }
+  }
+  // Otherwise, we attempt to reconstruct the correct URL after the fact
+  $redirect_url = _webform_filter_values($redirect_url, $node, $submission, NULL, FALSE, TRUE);
+  $parsed_redirect_url = parse_url($redirect_url);
+  if (!empty($parsed_redirect_url['path'])) {
+    $parsed_redirect_url['path'] = urldecode($parsed_redirect_url['path']);
+  }
+  if (!empty($parsed_redirect_url['query'])) {
+    $query_components = array();
+    parse_str(urldecode($parsed_redirect_url['query']), $query_components);
+    $parsed_redirect_url['query'] = '';
+    $sep = '';
+    foreach ($query_components as $key => $val) {
+      $parsed_redirect_url['query'] .= $sep . urlencode($key) . '=' . urlencode($val);
+      $sep = '&';
+    }
+  }
+  return _webform_assemble_parsed_url($parsed_redirect_url);
+
+}
+
+/**
+ * Assemble the components of a URL parsed by parse_url into a string
+ *
+ * @param array $parsed_url
+ *   An array in the format returned by parse_url
+ * @return string
+ *   The passed array re-assembled as a string
+ */
+function _webform_assemble_parsed_url($parsed_url) {
+  $url = '';
+  $url .= (!empty($parsed_url['scheme'])) ? $parsed_url['scheme'] . '://' : '';
+  if ( !empty($parsed_url['user']) && !empty($parsed_url['pass']) ) {
+    $url .= urlencode(urldecode($parsed_url['user'])) . ':' . urlencode(urldecode($parsed_url['pass']));
+  }
+  $url .= (!empty($parsed_url['host'])) ? $parsed_url['host'] : '';
+  $url .= (!empty($parsed_url['port'])) ? ':' + $parsed_url['port'] : '';
+  $url .= (!empty($parsed_url['path'])) ? $parsed_url['path'] : '';
+  $url .= (!empty($parsed_url['query'])) ? '?' . $parsed_url['query'] : '';
+  $url .= (!empty($parsed_url['fragment'])) ? '#' . $parsed_url['fragment'] : '';
+  return $url;
+}
+
+
+/**
  * Post processes the submission tree with any updates from components.
  *
  * @param $node
