Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1017
diff -u -r1.1017 common.inc
--- includes/common.inc	13 Oct 2009 21:16:42 -0000	1.1017
+++ includes/common.inc	14 Oct 2009 03:02:17 -0000
@@ -620,14 +620,30 @@
  * Drupal will ensure that messages set by drupal_set_message() and other
  * session data are written to the database before the user is redirected.
  *
- * This function ends the request; use it instead of a return in your menu callback.
+ * This function ends the request; use it instead of a return in your menu
+ * callback.
  *
  * @param $path
  *   A Drupal path or a full URL.
- * @param $query
- *   A query string component, if any.
- * @param $fragment
- *   A destination fragment identifier (named anchor).
+ * @param $options
+ *   An associative array of additional options, with the following keys:
+ *   - 'query': An array of query key/value-pairs (without any URL-encoding) to
+ *     append to the link.
+ *   - 'fragment': A fragment identifier (or named anchor) to append to the
+ *     link. Do not include the leading '#' character.
+ *   - 'alias': Defaults to FALSE. Whether the given path is a URL alias
+ *     already.
+ *   - 'external': Whether the given path is an external URL.
+ *   - 'language': An optional language object. Used to build the URL to link to
+ *     and look up the proper alias for the link.
+ *   - 'https': Whether this URL should point to a secure location. If not
+ *     specified, the current scheme is used, so the user stays on http or https
+ *     respectively. TRUE enforces HTTPS and FALSE enforces HTTP, but HTTPS can
+ *     only be enforced when the variable 'https' is set to TRUE.
+ *   - 'base_url': Only used internally, to modify the base URL when a language
+ *     dependent URL requires so.
+ *   - 'prefix': Only used internally, to modify the path when a language
+ *     dependent URL requires so.
  * @param $http_response_code
  *   Valid values for an actual "goto" as per RFC 2616 section 10.3 are:
  *   - 301 Moved Permanently (the recommended value for most redirects)
@@ -640,22 +656,23 @@
  *   Note: Other values are defined by RFC 2616, but are rarely used and poorly
  *   supported.
  * @see drupal_get_destination()
+ * @see url()
  */
-function drupal_goto($path = '', array $query = array(), $fragment = NULL, $http_response_code = 302) {
+function drupal_goto($path = '', $options = array(), $http_response_code = 302) {
   if (isset($_GET['destination'])) {
-    extract(drupal_parse_url(urldecode($_GET['destination'])));
+    // Pull in the information from $_GET and override the function arguments.
+    $destination = drupal_parse_url(urldecode($_GET['destination']));
+    $path = $destination['path'];
+    $options['query'] = $destination['query'];
+    $options['fragment'] = $destination['fragment'];
   }
 
-  $args = array(
-    'path' => &$path,
-    'query' => &$query,
-    'fragment' => &$fragment,
-    'http_response_code' => &$http_response_code,
-  );
-  drupal_alter('drupal_goto', $args);
-
-  $url = url($path, array('query' => $query, 'fragment' => $fragment, 'absolute' => TRUE));
-
+  // Allow modules to alter the destination, but not force a relative link.
+  drupal_alter('drupal_goto', $path, $options, $http_response_code);
+
+  // The Location header requires an absolute link.
+  $options['absolute'] = TRUE;
+  $url = url($path, $options);
   header('Location: ' . $url, TRUE, $http_response_code);
 
   // The "Location" header sends a redirect status code to the HTTP daemon. In
Index: modules/user/user.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.pages.inc,v
retrieving revision 1.58
diff -u -r1.58 user.pages.inc
--- modules/user/user.pages.inc	10 Oct 2009 16:48:39 -0000	1.58
+++ modules/user/user.pages.inc	14 Oct 2009 03:02:22 -0000
@@ -293,7 +293,7 @@
     unset($_GET['destination']);
   }
   // Note: We redirect from user/uid/edit to user/uid/cancel to make the tabs disappear.
-  $form_state['redirect'] = array("user/" . $form['#user']->uid . "/cancel", $destination);
+  $form_state['redirect'] = array("user/" . $form['#user']->uid . "/cancel", array('query' => $destination));
 }
 
 /**
Index: modules/simpletest/tests/common_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common_test.module,v
retrieving revision 1.5
diff -u -r1.5 common_test.module
--- modules/simpletest/tests/common_test.module	13 Oct 2009 16:38:43 -0000	1.5
+++ modules/simpletest/tests/common_test.module	14 Oct 2009 03:02:19 -0000
@@ -63,9 +63,9 @@
 /**
  * Implement hook_drupal_goto_alter().
  */
-function common_test_drupal_goto_alter(&$args) {
-  if ($args['path'] == 'common-test/drupal_goto/fail') {
-    $args['path'] = 'common-test/drupal_goto/redirect';
+function common_test_drupal_goto_alter(&$path, &$options, &$http_response_code) {
+  if ($path == 'common-test/drupal_goto/fail') {
+    $path = 'common-test/drupal_goto/redirect';
   }
 }
 
Index: modules/simpletest/tests/session_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/session_test.module,v
retrieving revision 1.12
diff -u -r1.12 session_test.module
--- modules/simpletest/tests/session_test.module	11 Sep 2009 04:45:23 -0000	1.12
+++ modules/simpletest/tests/session_test.module	14 Oct 2009 03:02:19 -0000
@@ -156,7 +156,7 @@
  * Force the redirection to go to a non-secure page after being on a secure
  * page through https.php.
  */
-function session_test_drupal_goto_alter(&$args) {
+function session_test_drupal_goto_alter(&$path, &$options, &$http_response_code) {
   global $base_insecure_url;
-  $args['path'] = $base_insecure_url . '/' . $args['path'];
+  $path = $base_insecure_url . '/' . $path;
 }
Index: modules/image/image.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/image/image.admin.inc,v
retrieving revision 1.12
diff -u -r1.12 image.admin.inc
--- modules/image/image.admin.inc	9 Oct 2009 01:00:00 -0000	1.12
+++ modules/image/image.admin.inc	14 Oct 2009 03:02:18 -0000
@@ -137,7 +137,10 @@
   // Load the configuration form for this option.
   if (isset($effect['form callback'])) {
     $path = 'admin/config/media/image-styles/edit/' . $form_state['image_style']['name'] . '/add/' . $form_state['values']['new'];
-    $form_state['redirect'] = array($path, array('weight' => $form_state['values']['weight']));
+    $form_state['redirect'] = array(
+      $path,
+      array('query' => array('weight' => $form_state['values']['weight']))
+    );
   }
   // If there's no form, immediately add the image effect.
   else {
Index: modules/system/system.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v
retrieving revision 1.86
diff -u -r1.86 system.api.php
--- modules/system/system.api.php	13 Oct 2009 21:34:15 -0000	1.86
+++ modules/system/system.api.php	14 Oct 2009 03:02:21 -0000
@@ -2236,21 +2236,42 @@
 /**
  * Change the page the user is sent to by drupal_goto().
  *
- * @param $args
- *   The array keys are the same as drupal_goto() arguments and the array can
- *   be changed.
- *   <code>
- *     $args = array(
- *       'path' => &$path,
- *       'query' => &$query,
- *       'fragment' => &$fragment,
- *       'http_response_code' => &$http_response_code,
- *     );
- *   </code>
+ * @param $path
+ *   A Drupal path or a full URL.
+ * @param $options
+ *   An associative array of additional options, with the following keys:
+ *   - 'query': An array of query key/value-pairs (without any URL-encoding) to
+ *     append to the link.
+ *   - 'fragment': A fragment identifier (or named anchor) to append to the
+ *     link. Do not include the leading '#' character.
+ *   - 'alias': Defaults to FALSE. Whether the given path is a URL alias
+ *     already.
+ *   - 'external': Whether the given path is an external URL.
+ *   - 'language': An optional language object. Used to build the URL to link to
+ *     and look up the proper alias for the link.
+ *   - 'https': Whether this URL should point to a secure location. If not
+ *     specified, the current scheme is used, so the user stays on http or https
+ *     respectively. TRUE enforces HTTPS and FALSE enforces HTTP, but HTTPS can
+ *     only be enforced when the variable 'https' is set to TRUE.
+ *   - 'base_url': Only used internally, to modify the base URL when a language
+ *     dependent URL requires so.
+ *   - 'prefix': Only used internally, to modify the path when a language
+ *     dependent URL requires so.
+ * @param $http_response_code
+ *   Valid values for an actual "goto" as per RFC 2616 section 10.3 are:
+ *   - 301 Moved Permanently (the recommended value for most redirects)
+ *   - 302 Found (default in Drupal and PHP, sometimes used for spamming search
+ *         engines)
+ *   - 303 See Other
+ *   - 304 Not Modified
+ *   - 305 Use Proxy
+ *   - 307 Temporary Redirect (alternative to "503 Site Down for Maintenance")
+ *   Note: Other values are defined by RFC 2616, but are rarely used and poorly
+ *   supported.
  */
-function hook_drupal_goto_alter(array $args) {
+function hook_drupal_goto_alter(&$path, &$options, &$http_response_code) {
   // A good addition to misery module.
-  $args['http_response_code'] = 500;
+  $http_response_code = 500;
 }
 
 /**
Index: modules/taxonomy/taxonomy.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.admin.inc,v
retrieving revision 1.72
diff -u -r1.72 taxonomy.admin.inc
--- modules/taxonomy/taxonomy.admin.inc	9 Oct 2009 01:00:05 -0000	1.72
+++ modules/taxonomy/taxonomy.admin.inc	14 Oct 2009 03:02:22 -0000
@@ -391,7 +391,7 @@
       '#type' => 'submit',
       '#value' => t('Reset to alphabetical')
     );
-    $form_state['redirect'] = array($_GET['q'], (isset($_GET['page']) ? array('page' => $_GET['page']) : ''));
+    $form_state['redirect'] = array($_GET['q'], (isset($_GET['page']) ? array('query' => array('page' => $_GET['page'])) : ''));
   }
 
   return $form;
Index: modules/node/node.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.pages.inc,v
retrieving revision 1.87
diff -u -r1.87 node.pages.inc
--- modules/node/node.pages.inc	11 Oct 2009 03:07:18 -0000	1.87
+++ modules/node/node.pages.inc	14 Oct 2009 03:02:18 -0000
@@ -302,7 +302,7 @@
     unset($_GET['destination']);
   }
   $node = $form['#node'];
-  $form_state['redirect'] = array('node/' . $node->nid . '/delete', $destination);
+  $form_state['redirect'] = array('node/' . $node->nid . '/delete', array('query' => $destination));
 }
 
 
Index: modules/openid/openid.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/openid/openid.module,v
retrieving revision 1.63
diff -u -r1.63 openid.module
--- modules/openid/openid.module	10 Oct 2009 16:48:38 -0000	1.63
+++ modules/openid/openid.module	14 Oct 2009 03:02:18 -0000
@@ -448,7 +448,7 @@
       // We'll want to redirect back to the same place.
       $destination = drupal_get_destination();
       unset($_GET['destination']);
-      drupal_goto('user/register', $destination);
+      drupal_goto('user/register', array('query' => $destination));
     }
     else {
       unset($form_state['values']['response']);
