From 73170a4f7b0b40ae76553d5a393ab913164bdc09 Mon Sep 17 00:00:00 2001
From: Bram Goffings <bramgoffings@gmail.com>
Date: Sat, 18 Aug 2012 10:20:08 +0200
Subject: [PATCH] drupal goto

---
 core/includes/common.inc                           |  8 +--
 core/includes/form.inc                             | 14 +++++
 core/lib/Drupal/Core/CoreBundle.php                |  1 +
 .../EventSubscriber/MaintenanceModeSubscriber.php  |  8 ++-
 .../Core/EventSubscriber/ResponseSubscriber.php    | 70 ++++++++++++++++++++++
 core/modules/aggregator/aggregator.admin.inc       |  3 +-
 core/modules/comment/comment.admin.inc             |  3 +-
 core/modules/comment/comment.pages.inc             | 15 ++---
 core/modules/image/image.admin.inc                 |  4 +-
 core/modules/language/language.admin.inc           |  3 +-
 core/modules/node/node.pages.inc                   |  3 +-
 core/modules/openid/openid.module                  |  8 ++-
 core/modules/openid/openid.pages.inc               |  4 +-
 core/modules/openid/tests/openid_test.module       |  6 +-
 core/modules/overlay/overlay.module                |  5 +-
 core/modules/search/search.pages.inc               |  4 +-
 core/modules/shortcut/shortcut.admin.inc           |  3 +-
 core/modules/simpletest/simpletest.pages.inc       |  5 +-
 core/modules/system/system.admin.inc               | 17 +++---
 core/modules/system/system.module                  | 11 ++--
 .../tests/modules/common_test/common_test.module   | 24 +++++---
 .../tests/modules/system_test/system_test.module   |  4 +-
 core/modules/toolbar/toolbar.module                |  4 +-
 core/modules/update/update.manager.inc             |  3 +-
 .../lib/Drupal/user/RegisterFormController.php     |  2 +-
 core/modules/user/user.module                      | 16 ++---
 core/modules/user/user.pages.inc                   | 13 ++--
 27 files changed, 192 insertions(+), 69 deletions(-)
 create mode 100644 core/lib/Drupal/Core/EventSubscriber/ResponseSubscriber.php

diff --git a/core/includes/common.inc b/core/includes/common.inc
index 17e1363..ff39d7c 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -502,14 +502,14 @@ function drupal_http_build_query(array $query, $parent = '') {
 }
 
 /**
- * Prepares a 'destination' URL query parameter for use with drupal_goto().
+ * Prepares a 'destination' URL query parameter for use with RedirectResponse.
  *
  * Used to direct the user back to the referring page after completing a form.
  * By default the current URL is returned. If a destination exists in the
  * previous request, that destination is returned. As such, a destination can
  * persist across multiple pages.
  *
- * @see drupal_goto()
+ * @see RedirectResponse()
  */
 function drupal_get_destination() {
   $destination = &drupal_static(__FUNCTION__);
@@ -563,7 +563,7 @@ function drupal_get_destination() {
  *   - 'fragment': The fragment of $url, if existent.
  *
  * @see url()
- * @see drupal_goto()
+ * @see RedirectResponse()
  * @ingroup php_wrappers
  */
 function drupal_parse_url($url) {
@@ -2372,8 +2372,6 @@ function l($text, $path, array $options = array()) {
  * There should rarely be a reason to call exit instead of drupal_exit();
  *
  * @param $destination
- *   If this function is called from drupal_goto(), then this argument
- *   will be a fully-qualified URL that is the destination of the redirect.
  *   This should be passed along to hook_exit() implementations.
  */
 function drupal_exit($destination = NULL) {
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 47c14ab..18e5e25 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Utility\Color;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * @defgroup forms Form builder functions
@@ -342,7 +343,11 @@ function drupal_build_form($form_id, &$form_state) {
       $form_state_before_retrieval = $form_state;
     }
 
+    // We are dealing with a redirect which is an object rather than an array.
     $form = drupal_retrieve_form($form_id, $form_state);
+    if (is_object($form) && is_a($form, 'Symfony\Component\HttpFoundation\RedirectResponse')) {
+      return $form;
+    }
     drupal_prepare_form($form_id, $form, $form_state);
 
     // form_set_cache() removes uncacheable $form_state keys defined in
@@ -456,6 +461,9 @@ function form_state_defaults() {
  */
 function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {
   $form = drupal_retrieve_form($form_id, $form_state);
+  if (is_object($form) && is_a($form, 'Symfony\Component\HttpFoundation\RedirectResponse')) {
+    return $form;
+  }
 
   // If only parts of the form will be returned to the browser (e.g., Ajax or
   // RIA clients), re-use the old #build_id to not require client-side code to
@@ -699,6 +707,9 @@ function drupal_form_submit($form_id, &$form_state) {
 
   $form_state['programmed'] = TRUE;
   $form = drupal_retrieve_form($form_id, $form_state);
+  if (is_object($form) && is_a($form, 'Symfony\Component\HttpFoundation\RedirectResponse')) {
+    return $form;
+  }
   // Programmed forms are always submitted.
   $form_state['submitted'] = TRUE;
 
@@ -815,6 +826,9 @@ function drupal_retrieve_form($form_id, &$form_state) {
   // If $callback was returned by a hook_forms() implementation, call it.
   // Otherwise, call the function named after the form id.
   $form = call_user_func_array($callback, $args);
+  if (is_object($form) && is_a($form, 'Symfony\Component\HttpFoundation\RedirectResponse')) {
+    return $form;
+  }
   $form['#form_id'] = $form_id;
 
   return $form;
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index b0830a0..0c595f7 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -58,6 +58,7 @@ class CoreBundle extends Bundle
     $dispatcher->addSubscriber(new \Drupal\Core\EventSubscriber\LegacyControllerSubscriber());
     $dispatcher->addSubscriber(new \Drupal\Core\EventSubscriber\FinishResponseSubscriber());
     $dispatcher->addSubscriber(new \Drupal\Core\EventSubscriber\RequestCloseSubscriber());
+    $dispatcher->addSubscriber(new \Drupal\Core\EventSubscriber\ResponseSubscriber());
     $container->set('content_negotiation', $content_negotation);
     $dispatcher->addSubscriber(\Drupal\Core\ExceptionController::getExceptionListener($container));
     /*
diff --git a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php
index d4eabfb..92b53e2 100644
--- a/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/MaintenanceModeSubscriber.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\EventSubscriber;
 
 use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\KernelEvents;
 use Symfony\Component\HttpKernel\Event\GetResponseEvent;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -32,7 +33,12 @@ class MaintenanceModeSubscriber implements EventSubscriberInterface {
     // be used to change the path. Code later will not use the $read_only_path
     // variable.
     $read_only_path = !empty($path) ? $path : $event->getRequest()->attributes->get('system_path');
-    drupal_alter('menu_site_status', $status, $read_only_path);
+    $redirect_path = $read_only_path;
+    drupal_alter('menu_site_status', $status, $read_only_path, $redirect_path);
+
+    if ($redirect_path != $read_only_path) {
+      $event->setResponse(new RedirectResponse($redirect_path));
+    }
 
     // Only continue if the site is online.
     if ($status != MENU_SITE_ONLINE) {
diff --git a/core/lib/Drupal/Core/EventSubscriber/ResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ResponseSubscriber.php
new file mode 100644
index 0000000..ac01e63
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/ResponseSubscriber.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\EventSubscriber\ResponseSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Access subscriber for controller requests.
+ */
+class ResponseSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Allows manipulation of the response object when performing a redirect.
+   *
+   * @param Symfony\Component\HttpKernel\Event\FilterResponseEvent $event
+   *   The Event to process.
+   */
+  public function onKernelResponse(FilterResponseEvent $event) {
+
+    $response = $event->getResponse();
+
+    if (get_class($response) == 'Symfony\Component\HttpFoundation\RedirectResponse') {
+      $request = $event->getRequest();
+
+      // Get the path we are redirecting too.
+      $target_path = $response->getTargetUrl();
+
+      $options = array();
+      // @todo update this.
+      $destination = $request->query->get('destination', '');
+      // A destination in $_GET always overrides the function arguments.
+      // We do not allow absolute URLs to be passed via $_GET, as this can be an
+      // attack vector.
+      if (!empty($destination)) {
+        $destination = drupal_parse_url($destination);
+        $path = $destination['path'];
+        $options['query'] = $destination['query'];
+        $options['fragment'] = $destination['fragment'];
+      }
+      // @todo should this be renamed. Also we don't have $options available really
+      // or $status and $status also can't be updated.
+      drupal_alter('drupal_goto', $target_path, $options, $status);
+      // The 'Location' HTTP header must be absolute.
+      $options['absolute'] = TRUE;
+
+      $url = url($target_path, $options);
+
+      // We don't have this method available.
+      $response->setTargetUrl($url);
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::RESPONSE][] = array('onKernelResponse', 100);
+    return $events;
+  }
+}
diff --git a/core/modules/aggregator/aggregator.admin.inc b/core/modules/aggregator/aggregator.admin.inc
index 718e79c..1f995dc 100644
--- a/core/modules/aggregator/aggregator.admin.inc
+++ b/core/modules/aggregator/aggregator.admin.inc
@@ -7,6 +7,7 @@
 
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Drupal\aggregator\Plugin\FetcherManager;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Page callback: Displays the aggregator administration page.
@@ -418,7 +419,7 @@ function aggregator_admin_refresh_feed($feed) {
   }
 
   aggregator_refresh($feed);
-  drupal_goto('admin/config/services/aggregator');
+  return new RedirectResponse('admin/config/services/aggregator');
 }
 
 /**
diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc
index 6210cc5..4a56e14 100644
--- a/core/modules/comment/comment.admin.inc
+++ b/core/modules/comment/comment.admin.inc
@@ -7,6 +7,7 @@
 
 use Drupal\comment\Comment;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Page callback: Presents an administrative comment listing.
@@ -226,7 +227,7 @@ function comment_multiple_delete_confirm($form, &$form_state) {
 
   if (!$comment_counter) {
     drupal_set_message(t('There do not appear to be any comments to delete, or your selected comment was deleted by another administrator.'));
-    drupal_goto('admin/content/comment');
+    return new RedirectResponse('admin/content/comment');
   }
   else {
     return confirm_form($form,
diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc
index ed91d23..951ca7b 100644
--- a/core/modules/comment/comment.pages.inc
+++ b/core/modules/comment/comment.pages.inc
@@ -8,6 +8,7 @@
 use Drupal\node\Node;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Form constructor for the comment reply form.
@@ -47,7 +48,7 @@ function comment_reply(Node $node, $pid = NULL) {
     }
     else {
       drupal_set_message(t('You are not authorized to post comments.'), 'error');
-      drupal_goto("node/$node->nid");
+      return new RedirectResponse("node/$node->nid");
     }
   }
   else {
@@ -62,7 +63,7 @@ function comment_reply(Node $node, $pid = NULL) {
           if ($comment->nid != $node->nid) {
             // Attempting to reply to a comment not belonging to the current nid.
             drupal_set_message(t('The comment you are replying to does not exist.'), 'error');
-            drupal_goto("node/$node->nid");
+            return new RedirectResponse("node/$node->nid");
           }
           // Display the parent comment
           $comment->node_type = 'comment_node_' . $node->type;
@@ -72,12 +73,12 @@ function comment_reply(Node $node, $pid = NULL) {
         }
         else {
           drupal_set_message(t('The comment you are replying to does not exist.'), 'error');
-          drupal_goto("node/$node->nid");
+          return new RedirectResponse("node/$node->nid");
         }
       }
       else {
         drupal_set_message(t('You are not authorized to view comments.'), 'error');
-        drupal_goto("node/$node->nid");
+        return new RedirectResponse("node/$node->nid");
       }
     }
     // This is the case where the comment is in response to a node. Display the node.
@@ -88,14 +89,14 @@ function comment_reply(Node $node, $pid = NULL) {
     // Should we show the reply box?
     if ($node->comment != COMMENT_NODE_OPEN) {
       drupal_set_message(t("This discussion is closed: you can't post new comments."), 'error');
-      drupal_goto("node/$node->nid");
+      return new RedirectResponse("node/$node->nid");
     }
     elseif (user_access('post comments')) {
       $build['comment_form'] = comment_add($node, $pid);
     }
     else {
       drupal_set_message(t('You are not authorized to post comments.'), 'error');
-      drupal_goto("node/$node->nid");
+      return new RedirectResponse("node/$node->nid");
     }
   }
 
@@ -124,7 +125,7 @@ function comment_approve($cid) {
     comment_save($comment);
 
     drupal_set_message(t('Comment approved.'));
-    drupal_goto('node/' . $comment->nid);
+    return new RedirectResponse('node/' . $comment->nid);
   }
   throw new NotFoundHttpException();
 }
diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc
index d0ef114..8e58110 100644
--- a/core/modules/image/image.admin.inc
+++ b/core/modules/image/image.admin.inc
@@ -5,6 +5,8 @@
  * Administration pages for image settings.
  */
 
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
 /**
  * Menu callback; Listing of all current image styles.
  */
@@ -339,7 +341,7 @@ function image_effect_form($form, &$form_state, $style, $effect) {
 
   // If no configuration for this image effect, return to the image style page.
   if (!isset($effect['form callback'])) {
-    drupal_goto('admin/config/media/image-styles/edit/' . $style['name']);
+    return new RedirectResponse('admin/config/media/image-styles/edit/' . $style['name']);
   }
 
   $form['#tree'] = TRUE;
diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc
index a601d00..86d4619 100644
--- a/core/modules/language/language.admin.inc
+++ b/core/modules/language/language.admin.inc
@@ -6,6 +6,7 @@
  */
 
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * User interface for the language overview screen.
@@ -391,7 +392,7 @@ function language_admin_delete_form($form, &$form_state, $language) {
 
   if (language_default()->langcode == $langcode) {
     drupal_set_message(t('The default language cannot be deleted.'));
-    drupal_goto('admin/config/regional/language');
+    return new RedirectResponse('admin/config/regional/language');
   }
 
   // For other languages, warn the user that data loss is ahead.
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index b2e1e4b..02e31fc 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -10,6 +10,7 @@
  */
 
 use Drupal\node\Node;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Page callback: Presents the node editing form.
@@ -40,7 +41,7 @@ function node_add_page() {
   // Bypass the node/add listing if only one content type is available.
   if (count($content) == 1) {
     $type = array_shift($content);
-    drupal_goto('node/add/' . $type->type);
+    return new RedirectResponse('node/add/' . $type->type);
   }
   return array('#theme' => 'node_add_list', '#content' => $content);
 }
diff --git a/core/modules/openid/openid.module b/core/modules/openid/openid.module
index 5098216..e555356 100644
--- a/core/modules/openid/openid.module
+++ b/core/modules/openid/openid.module
@@ -5,6 +5,8 @@
  * Implement OpenID Relying Party support for Drupal
  */
 
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
 /**
  * Implements hook_menu().
  */
@@ -741,7 +743,7 @@ function openid_authentication($response) {
     }
     else {
       module_invoke_all('openid_response', $response, $form_state['user']);
-      drupal_goto();
+      return new RedirectResponse('<front>');
     }
 
     $messages = drupal_get_messages('error');
@@ -763,13 +765,13 @@ function openid_authentication($response) {
     // registration page and prefill with the values we received.
     $destination = drupal_get_destination();
     unset($_GET['destination']);
-    drupal_goto('user/register', array('query' => $destination));
+    return new RedirectResponse('user/register', array('query' => $destination));
   }
   else {
     drupal_set_message(t('Only site administrators can create new user accounts.'), 'error');
     module_invoke_all('openid_response', $response, NULL);
   }
-  drupal_goto();
+  return new RedirectResponse('<front>');
 }
 
 function openid_association_request($public) {
diff --git a/core/modules/openid/openid.pages.inc b/core/modules/openid/openid.pages.inc
index 885fe1d..c8fde64 100644
--- a/core/modules/openid/openid.pages.inc
+++ b/core/modules/openid/openid.pages.inc
@@ -5,6 +5,8 @@
  * User page callbacks for the openid module.
  */
 
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
 /**
  * Menu callback; Process an OpenID authentication.
  */
@@ -20,7 +22,7 @@ function openid_authentication_page() {
       drupal_set_message(t('OpenID login cancelled.'));
       break;
   }
-  drupal_goto();
+  return new RedirectResponse('<front>');
 }
 
 /**
diff --git a/core/modules/openid/tests/openid_test.module b/core/modules/openid/tests/openid_test.module
index 89f3ddf..edc9390 100644
--- a/core/modules/openid/tests/openid_test.module
+++ b/core/modules/openid/tests/openid_test.module
@@ -228,7 +228,7 @@ function openid_test_redirect($count = 0) {
     $url = url('openid-test/redirect/' . --$count, array('absolute' => TRUE));
   }
   $http_response_code = variable_get('openid_test_redirect_http_reponse_code', 301);
-  return new RedirectResponse($url, $http_response_code);
+  return new RedirectResponse($url, array(), $http_response_code);
 }
 
 /**
@@ -306,7 +306,7 @@ function _openid_test_endpoint_authenticate() {
       'openid.mode' => 'error',
       'openid.error' => 'Unexpted identity',
     );
-    return new RedirectResponse(url($_REQUEST['openid_return_to'], array('query' => $response, 'external' => TRUE)));
+    return new RedirectResponse($_REQUEST['openid_return_to'], array('query' => $response, 'external' => TRUE));
   }
 
   // Generate unique identifier for this authentication.
@@ -346,7 +346,7 @@ function _openid_test_endpoint_authenticate() {
 
   // Put the signed message into the query string of a URL supplied by the
   // Relying Party, and redirect the user.
-  return new RedirectResponse(url($_REQUEST['openid_return_to'], array('query' => $response, 'external', TRUE)));
+  return new RedirectResponse($_REQUEST['openid_return_to'], array('query' => $response, 'external' => TRUE));
 }
 
 /**
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 3aaed7d..4211557 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -7,6 +7,7 @@
 
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Implements hook_help().
@@ -133,7 +134,7 @@ function overlay_init() {
     // <front>#overlay=admin/modules to actually enable the overlay.
     if (isset($_SESSION['overlay_enable_redirect']) && $_SESSION['overlay_enable_redirect']) {
       unset($_SESSION['overlay_enable_redirect']);
-      drupal_goto('<front>', array('fragment' => 'overlay=' . $current_path));
+      return new RedirectResponse('<front>', array('fragment' => 'overlay=' . $current_path));
     }
 
     if (isset($_GET['render']) && $_GET['render'] == 'overlay') {
@@ -343,7 +344,7 @@ function overlay_user_dismiss_message() {
   $account->save();
   drupal_set_message(t('The message has been dismissed. You can change your overlay settings at any time by visiting your profile page.'));
   // Destination is normally given. Go to the user profile as a fallback.
-  drupal_goto('user/' . $user->uid . '/edit');
+  return new RedirectResponse('user/' . $user->uid . '/edit');
 }
 
 /**
diff --git a/core/modules/search/search.pages.inc b/core/modules/search/search.pages.inc
index 337fe85..a8d8876 100644
--- a/core/modules/search/search.pages.inc
+++ b/core/modules/search/search.pages.inc
@@ -5,6 +5,8 @@
  * User page callbacks for the search module.
  */
 
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
 /**
  * Menu callback; presents the search form and/or search results.
  *
@@ -40,7 +42,7 @@ function search_view($module = NULL, $keys = '') {
     if ($keys) {
       $path .= '/' . $keys;
     }
-    drupal_goto($path);
+    return new RedirectResponse($path);
   }
 
   // Default results output is an empty string.
diff --git a/core/modules/shortcut/shortcut.admin.inc b/core/modules/shortcut/shortcut.admin.inc
index 3345c59..27414d7 100644
--- a/core/modules/shortcut/shortcut.admin.inc
+++ b/core/modules/shortcut/shortcut.admin.inc
@@ -6,6 +6,7 @@
  */
 
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Form callback: builds the form for switching shortcut sets.
@@ -690,7 +691,7 @@ function shortcut_link_add_inline($shortcut_set) {
     else {
       drupal_set_message(t('Unable to add a shortcut for %title.', array('%title' => $link['link_title'])));
     }
-    drupal_goto();
+    return new RedirectResponse('<front>');
   }
 
   throw new AccessDeniedHttpException();
diff --git a/core/modules/simpletest/simpletest.pages.inc b/core/modules/simpletest/simpletest.pages.inc
index a98b445..c2e7f40 100644
--- a/core/modules/simpletest/simpletest.pages.inc
+++ b/core/modules/simpletest/simpletest.pages.inc
@@ -5,6 +5,8 @@
  * Page callbacks for simpletest module.
  */
 
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
 /**
  * List tests arranged in groups that can be selected and run.
  */
@@ -208,8 +210,7 @@ function simpletest_result_form($form, &$form_state, $test_id) {
   $results = array();
   if (is_numeric($test_id) && !$results = simpletest_result_get($test_id)) {
     drupal_set_message(t('No test results to display.'), 'error');
-    drupal_goto('admin/config/development/testing');
-    return $form;
+    return new RedirectResponse('admin/config/development/testing');
   }
 
   // Load all classes and include CSS.
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 8aa3ed4..3283a46 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -8,6 +8,7 @@
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Menu callback; Provide the administration overview page.
@@ -291,7 +292,7 @@ function system_theme_enable() {
     else {
       drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
     }
-    drupal_goto('admin/appearance');
+    return new RedirectResponse('admin/appearance');
   }
   throw new AccessDeniedHttpException();
 }
@@ -319,7 +320,7 @@ function system_theme_disable() {
     else {
       drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
     }
-    drupal_goto('admin/appearance');
+    return new RedirectResponse('admin/appearance');
   }
   throw new AccessDeniedHttpException();
 }
@@ -366,7 +367,7 @@ function system_theme_default() {
     else {
       drupal_set_message(t('The %theme theme was not found.', array('%theme' => $theme)), 'error');
     }
-    drupal_goto('admin/appearance');
+    return new RedirectResponse('admin/appearance');
   }
   throw new AccessDeniedHttpException();
 }
@@ -1342,7 +1343,7 @@ function system_modules_uninstall_validate($form, &$form_state) {
   // Form submitted, but no modules selected.
   if (!count(array_filter($form_state['values']['uninstall']))) {
     drupal_set_message(t('No modules selected.'), 'error');
-    drupal_goto('admin/modules/uninstall');
+    return new RedirectResponse('admin/modules/uninstall');
   }
 }
 
@@ -1652,7 +1653,7 @@ function system_run_cron_submit($form, &$form_state) {
     drupal_set_message(t('Cron run failed.'), 'error');
   }
 
-  drupal_goto('admin/config/system/cron');
+  return new RedirectResponse('admin/config/system/cron');
 }
 
 /**
@@ -2318,7 +2319,7 @@ function system_run_cron() {
     drupal_set_message(t('Cron run failed.'), 'error');
   }
 
-  drupal_goto('admin/reports/status');
+  return new RedirectResponse('admin/reports/status');
 }
 
 /**
@@ -3060,7 +3061,7 @@ function system_actions_manage_form_submit($form, &$form_state) {
  */
 function system_actions_configure($form, &$form_state, $action = NULL) {
   if ($action === NULL) {
-    drupal_goto('admin/config/system/actions');
+    return new RedirectResponse('admin/config/system/actions');
   }
 
   $actions_map = actions_actions_map(actions_list());
@@ -3207,7 +3208,7 @@ function system_action_delete_orphans_post($orphaned) {
  */
 function system_actions_remove_orphans() {
   actions_synchronize(TRUE);
-  drupal_goto('admin/config/system/actions/manage');
+  return new RedirectResponse('admin/config/system/actions/manage');
 }
 
 /**
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 3c434ae..1cecea0 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -9,6 +9,7 @@ use Drupal\Core\Utility\ModuleInfo;
 
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Maximum age of temporary files in seconds.
@@ -1913,8 +1914,8 @@ function _system_themes_access($theme) {
  * or to call system_authorized_init() and then redirect to authorize.php,
  * using the URL from system_authorized_get_url(). Redirecting yourself is
  * necessary when your authorized operation is being triggered by a form
- * submit handler, since calling drupal_goto() in a submit handler is a bad
- * idea, and you should instead set $form_state['redirect'].
+ * submit handler, since calling new RedirectResponse in a submit handler is a
+ * bad idea, and you should instead set $form_state['redirect'].
  *
  * Once the SESSION is setup for the operation and the user is redirected to
  * authorize.php, they will be prompted for their connection credentials (core
@@ -2001,7 +2002,7 @@ function system_authorized_batch_processing_url() {
  */
 function system_authorized_run($callback, $file, $arguments = array(), $page_title = NULL) {
   system_authorized_init($callback, $file, $arguments, $page_title);
-  drupal_goto(system_authorized_get_url());
+  return new RedirectResponse(system_authorized_get_url());
 }
 
 /**
@@ -3245,7 +3246,7 @@ function system_admin_compact_mode() {
  */
 function system_admin_compact_page($mode = 'off') {
   user_cookie_save(array('admin_compact_mode' => ($mode == 'on')));
-  drupal_goto();
+  return new RedirectResponse('<front>');
 }
 
 /**
@@ -3652,7 +3653,7 @@ function system_goto_action_submit($form, $form_state) {
  * @ingroup actions
  */
 function system_goto_action($entity, $context) {
-  drupal_goto(token_replace($context['url'], $context));
+  return new RedirectResponse(token_replace($context['url'], $context));
 }
 
 /**
diff --git a/core/modules/system/tests/modules/common_test/common_test.module b/core/modules/system/tests/modules/common_test/common_test.module
index 187fee5..4086d75 100644
--- a/core/modules/system/tests/modules/common_test/common_test.module
+++ b/core/modules/system/tests/modules/common_test/common_test.module
@@ -5,6 +5,8 @@
  * Helper module for the Common tests.
  */
 
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
 /**
  * Implements hook_menu().
  */
@@ -35,8 +37,7 @@ function common_test_menu() {
   );
   $items['common-test/drupal_goto/redirect_fail'] = array(
     'title' => 'Drupal Goto Failure',
-    'page callback' => 'drupal_goto',
-    'page arguments' => array('common-test/drupal_goto/fail'),
+    'page callback' => 'common_test_drupal_goto_redirect_fail',
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
   );
@@ -62,28 +63,35 @@ function common_test_menu() {
 }
 
 /**
- * Redirect using drupal_goto().
+ * Redirect using RedirectResponse.
  */
 function common_test_drupal_goto_redirect() {
-  drupal_goto('common-test/drupal_goto');
+  return new RedirectResponse('common-test/drupal_goto');
+}
+
+/**
+ * Redirect using RedirectResponse.
+ */
+function common_test_drupal_goto_redirect_fail() {
+  return new RedirectResponse('common-test/drupal_goto/fail');
 }
 
 /**
- * Redirect using drupal_goto().
+ * Redirect using RedirectResponse.
  */
 function common_test_drupal_goto_redirect_advanced() {
-  drupal_goto('common-test/drupal_goto', array('query' => array('foo' => '123')), 301);
+  return new RedirectResponse('common-test/drupal_goto', array('query' => array('foo' => '123')), 301);
 }
 
 /**
- * Landing page for drupal_goto().
+ * Landing page for RedirectResponse.
  */
 function common_test_drupal_goto_land() {
   print "drupal_goto";
 }
 
 /**
- * Fail landing page for drupal_goto().
+ * Fail landing page for RedirectResponse.
  */
 function common_test_drupal_goto_land_fail() {
   print "drupal_goto_fail";
diff --git a/core/modules/system/tests/modules/system_test/system_test.module b/core/modules/system/tests/modules/system_test/system_test.module
index 444d54d..61187a5 100644
--- a/core/modules/system/tests/modules/system_test/system_test.module
+++ b/core/modules/system/tests/modules/system_test/system_test.module
@@ -1,5 +1,7 @@
 <?php
 
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
 /**
  * Implements hook_menu().
  */
@@ -384,5 +386,5 @@ function system_test_filetransfer_info() {
 function system_test_authorize_init_page($page_title) {
   $authorize_url = $GLOBALS['base_url'] . '/core/authorize.php';
   system_authorized_init('system_test_authorize_run', drupal_get_path('module', 'system_test') . '/system_test.module', array(), $page_title);
-  drupal_goto($authorize_url);
+  return new RedirectResponse($authorize_url);
 }
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 70f12bf..5c5f14c 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -5,6 +5,8 @@
  * Administration toolbar for quick access to top level administration items.
  */
 
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
 /**
  * Implements hook_help().
  */
@@ -74,7 +76,7 @@ function toolbar_toggle_page() {
   // Toggle the value in the cookie.
   setcookie('Drupal.toolbar.collapsed', !_toolbar_is_collapsed(), NULL, $base_path);
   // Redirect the user from where he used the toggle element.
-  drupal_goto();
+  return new RedirectResponse('<front>');
 }
 
 /**
diff --git a/core/modules/update/update.manager.inc b/core/modules/update/update.manager.inc
index 5720af7..e7dd712 100644
--- a/core/modules/update/update.manager.inc
+++ b/core/modules/update/update.manager.inc
@@ -38,6 +38,7 @@
 
 use Drupal\Core\Updater\Updater;
 use Drupal\Core\FileTransfer\Local;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * @defgroup update_manager_update Update Manager module: update
@@ -356,7 +357,7 @@ function update_manager_download_batch_finished($success, $results) {
   elseif ($success) {
     drupal_set_message(t('Updates downloaded successfully.'));
     $_SESSION['update_manager_update_projects'] = $results['projects'];
-    drupal_goto('admin/update/ready');
+    return new RedirectResponse('admin/update/ready');
   }
   else {
     // Ideally we're catching all Exceptions, so they should never see this,
diff --git a/core/modules/user/lib/Drupal/user/RegisterFormController.php b/core/modules/user/lib/Drupal/user/RegisterFormController.php
index 9c88aec..bb14aeb 100644
--- a/core/modules/user/lib/Drupal/user/RegisterFormController.php
+++ b/core/modules/user/lib/Drupal/user/RegisterFormController.php
@@ -32,7 +32,7 @@ class RegisterFormController extends AccountFormController {
 
     // If we aren't admin but already logged on, go to the user page instead.
     if (!$admin && $user->uid) {
-      drupal_goto('user/' . $user->uid);
+      return new RedirectResponse('user/' . $user->uid);
     }
 
     $form['#attached']['library'][] = array('system', 'jquery.cookie');
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 313affe..1ccd7cb 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -3,6 +3,7 @@
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\File\File;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * @file
@@ -1371,7 +1372,7 @@ function user_menu() {
 /**
  * Implements hook_menu_site_status_alter().
  */
-function user_menu_site_status_alter(&$menu_site_status, $path) {
+function user_menu_site_status_alter(&$menu_site_status, $path, &$redirect_path) {
   if ($menu_site_status == MENU_SITE_OFFLINE) {
     // If the site is offline, log out unprivileged users.
     if (user_is_logged_in() && !user_access('access site in maintenance mode')) {
@@ -1383,7 +1384,8 @@ function user_menu_site_status_alter(&$menu_site_status, $path) {
       switch ($path) {
         case 'user':
           // Forward anonymous user to login page.
-          drupal_goto('user/login');
+          $redirect_ath = 'user/login';
+          break;
         case 'user/login':
         case 'user/password':
           // Disable offline mode.
@@ -1401,11 +1403,11 @@ function user_menu_site_status_alter(&$menu_site_status, $path) {
   if (user_is_logged_in()) {
     if ($path == 'user/login') {
       // If user is logged in, redirect to 'user' instead of giving 403.
-      drupal_goto('user');
+      $redirect_path = 'user';
     }
-    if ($path == 'user/register') {
+    elseif ($path == 'user/register') {
       // Authenticated user should be redirected to user edit page.
-      drupal_goto('user/' . $GLOBALS['user']->uid . '/edit');
+      $redirect_path = 'user/' . $GLOBALS['user']->uid . '/edit';
     }
   }
 }
@@ -1578,7 +1580,7 @@ function user_login($form, &$form_state) {
 
   // If we are already logged on, go to the user page instead.
   if ($user->uid) {
-    drupal_goto('user/' . $user->uid);
+    return new RedirectResponse('user/' . $user->uid);
   }
 
   // Display login form:
@@ -2763,7 +2765,7 @@ function user_multiple_cancel_confirm($form, &$form_state) {
     drupal_set_message($message, $redirect ? 'error' : 'warning');
     // If only user 1 was selected, redirect to the overview.
     if ($redirect) {
-      drupal_goto('admin/people');
+      return new RedirectResponse('admin/people');
     }
   }
 
diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc
index 9121c44..712ce07 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -9,6 +9,7 @@ use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 
 /**
  * Menu callback; Retrieve a JSON object containing autocomplete suggestions for existing users.
@@ -115,7 +116,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
         drupal_set_message(t('The one-time login link you clicked is invalid.'));
       }
     }
-    drupal_goto();
+    return new RedirectResponse('<front>');
   }
   else {
     // Time out, in seconds, until login URL expires. Defaults to 24 hours =
@@ -128,7 +129,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
       // No time out for first time login.
       if ($account->login && $current - $timestamp > $timeout) {
         drupal_set_message(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'));
-        drupal_goto('user/password');
+        return new RedirectResponse('user/password');
       }
       elseif ($account->uid && $timestamp >= $account->login && $timestamp <= $current && $hashed_pass == user_pass_rehash($account->pass, $timestamp, $account->login)) {
         // First stage is a confirmation form, then login
@@ -143,7 +144,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
           // Let the user's password be changed without the current password check.
           $token = drupal_hash_base64(drupal_random_bytes(55));
           $_SESSION['pass_reset_' . $user->uid] = $token;
-          drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
+          return new RedirectResponse('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token)));
         }
         else {
           $form['message'] = array('#markup' => t('<p>This is a one-time login for %user_name and will expire on %expiration_date.</p><p>Click on this button to log in to the site and change your password.</p>', array('%user_name' => $account->name, '%expiration_date' => format_date($timestamp + $timeout))));
@@ -156,7 +157,7 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
       }
       else {
         drupal_set_message(t('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'));
-        drupal_goto('user/password');
+        return new RedirectResponse('user/password');
       }
     }
     else {
@@ -180,7 +181,7 @@ function user_logout() {
   // Destroy the current session, and reset $user to the anonymous user.
   session_destroy();
 
-  drupal_goto();
+  return new RedirectResponse('<front>');
 }
 
 /**
@@ -403,7 +404,7 @@ function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') {
     }
     else {
       drupal_set_message(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'));
-      drupal_goto("user/$account->uid/cancel");
+      return new RedirectResponse("user/$account->uid/cancel");
     }
   }
   throw new AccessDeniedHttpException();
-- 
1.7.11.msysgit.1

