diff --git a/core/core.services.yml b/core/core.services.yml index 2cd6077..6090933 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -365,6 +365,11 @@ services: - { name: event_subscriber } arguments: ['@language_manager'] scope: request + redirect_response_subscriber: + class: Drupal\Core\EventSubscriber\RedirectResponseSubscriber + tags: + - { name: event_subscriber } + scope: request request_close_subscriber: class: Drupal\Core\EventSubscriber\RequestCloseSubscriber tags: diff --git a/core/includes/batch.inc b/core/includes/batch.inc index 2152725..7c28aac 100644 --- a/core/includes/batch.inc +++ b/core/includes/batch.inc @@ -14,7 +14,8 @@ * @see batch_get() */ -use \Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\RedirectResponse; /** * Renders the batch processing page based on the current state of the batch. @@ -33,7 +34,7 @@ function _batch_page() { $batch = Drupal::service('batch.storage')->load($_REQUEST['id']); if (!$batch) { drupal_set_message(t('No active batch.'), 'error'); - drupal_goto(); + return new RedirectResponse(url('', array('absolute' => TRUE))); } } @@ -445,7 +446,10 @@ function _batch_finished() { } // Use drupal_redirect_form() to handle the redirection logic. - drupal_redirect_form($_batch['form_state']); + $redirect = drupal_redirect_form($_batch['form_state']); + if (is_object($redirect)) { + return $redirect; + } // If no redirection happened, redirect to the originating page. In case the // form needs to be rebuilt, save the final $form_state for diff --git a/core/includes/common.inc b/core/includes/common.inc index 667807a..2bc86dc 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -511,7 +511,7 @@ 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 url(). * * 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 @@ -524,7 +524,6 @@ function drupal_http_build_query(array $query, $parent = '') { * not available, the current path. * * @see current_path() - * @see drupal_goto() */ function drupal_get_destination() { $destination = &drupal_static(__FUNCTION__); @@ -578,7 +577,6 @@ function drupal_get_destination() { * - 'fragment': The fragment of $url, if existent. * * @see url() - * @see drupal_goto() * @ingroup php_wrappers */ function drupal_parse_url($url) { @@ -638,84 +636,6 @@ function drupal_encode_path($path) { } /** - * Sends the user to a different Drupal page. - * - * This issues an on-site HTTP redirect. The function makes sure the redirected - * URL is formatted correctly. - * - * If a destination was specified in the current request's URI (i.e., - * $_GET['destination']) then it will override the $path and $options values - * passed to this function. This provides the flexibility to build a link to - * user/login and override the default redirection so that the user is - * redirected to a specific path after logging in: - * @code - * $query = array('destination' => "node/$node->nid"); - * $link = l(t('Log in'), 'user/login', array('query' => $query)); - * @endcode - * - * 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. - * - * @param $path - * (optional) A Drupal path or a full URL, which will be passed to url() to - * compute the redirect for the URL. - * @param $options - * (optional) An associative array of additional URL options to pass to url(). - * @param $http_response_code - * (optional) The HTTP status code to use for the redirection, defaults to - * 302. The valid values for 3xx redirection status codes are defined in - * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3 RFC 2616 @endlink - * and the - * @link http://tools.ietf.org/html/draft-reschke-http-status-308-07 draft for the new HTTP status codes: @endlink - * - 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. - * - * @see drupal_get_destination() - * @see url() - */ -function drupal_goto($path = '', array $options = array(), $http_response_code = 302) { - // 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, with the following exception: - // - Absolute URLs that point to this site (i.e. same base URL and - // base path) are allowed. - if (isset($_GET['destination']) && (!url_is_external($_GET['destination']) || _external_url_is_local($_GET['destination']))) { - $destination = drupal_parse_url($_GET['destination']); - $path = $destination['path']; - $options['query'] = $destination['query']; - $options['fragment'] = $destination['fragment']; - } - - drupal_alter('drupal_goto', $path, $options, $http_response_code); - - // The 'Location' HTTP header must be absolute. - $options['absolute'] = TRUE; - - $url = Drupal::urlGenerator()->generateFromPath($path, $options); - - if (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL) { - drupal_session_commit(); - } - - $response = new RedirectResponse($url, $http_response_code); - // @todo We should not send the response here: http://drupal.org/node/1668866 - $response->sendHeaders(); - - // The "Location" header sends a redirect status code to the HTTP daemon. In - // some cases this can be wrong, so we make sure none of the code below the - // drupal_goto() call gets executed upon redirection. - exit; -} - -/** * Determines if an external URL points to this Drupal installation. * * @param $url diff --git a/core/includes/form.inc b/core/includes/form.inc index 90d47fb..4e0a313 100644 --- a/core/includes/form.inc +++ b/core/includes/form.inc @@ -14,6 +14,10 @@ use Drupal\Core\Template\Attribute; use Drupal\Core\Datetime\DrupalDateTime; use Drupal\Core\Utility\Color; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\Event\FilterResponseEvent; /** * @defgroup forms Form builder functions @@ -227,9 +231,8 @@ function drupal_get_form($form_arg) { * errors. * - redirect: Used to redirect the form on submission. It may either be a * string containing the destination URL, or an array of arguments - * compatible with drupal_goto(). See drupal_redirect_form() for complete - * information. - * - no_redirect: If set to TRUE the form will NOT perform a drupal_goto(), + * compatible with url(). See url() for complete information. + * - no_redirect: If set to TRUE the form will NOT perform a redirect, * even if 'redirect' is set. * - method: The HTTP form method to use for finding the input for this form. * May be 'post' or 'get'. Defaults to 'post'. Note that 'get' method @@ -413,7 +416,12 @@ function drupal_build_form($form_id, &$form_state) { // appropriate information persists to the next page request. // All of the handlers in the pipeline receive $form_state by reference and // can use it to know or update information about the state of the form. - drupal_process_form($form_id, $form, $form_state); + $response = drupal_process_form($form_id, $form, $form_state); + + // If the form returns some kind of response, deliver it. + if ($response instanceof Response) { + _drupal_form_send_response($response); + } // If this was a successful submission of a single-step form or the last step // of a multi-step form, then drupal_process_form() issued a redirect to @@ -858,6 +866,10 @@ 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 the form returns some kind of response, deliver it. + if ($form instanceof Response) { + _drupal_form_send_response($form); + } $form['#form_id'] = $form_id; return $form; @@ -941,7 +953,10 @@ function drupal_process_form($form_id, &$form, &$form_state) { } $batch['progressive'] = !$form_state['programmed']; - batch_process(); + $response = batch_process(); + if ($batch['progressive']) { + return $response; + } // Execution continues only for programmatic forms. // For 'regular' forms, we get redirected to the batch processing @@ -953,7 +968,10 @@ function drupal_process_form($form_id, &$form, &$form_state) { $form_state['executed'] = TRUE; // Redirect the form based on values in $form_state. - drupal_redirect_form($form_state); + $redirect = drupal_redirect_form($form_state); + if (is_object($redirect)) { + return $redirect; + } } // Don't rebuild or cache form submissions invoked via drupal_form_submit(). @@ -1245,10 +1263,10 @@ function drupal_validate_form($form_id, &$form, &$form_state) { * * Usually (for exceptions, see below) $form_state['redirect'] determines where * to redirect the user. This can be set either to a string (the path to - * redirect to), or an array of arguments for drupal_goto(). If - * $form_state['redirect'] is missing, the user is usually (again, see below for - * exceptions) redirected back to the page they came from, where they should see - * a fresh, unpopulated copy of the form. + * redirect to), or an array of arguments for url(). If $form_state['redirect'] + * is missing, the user is usually (again, see below for exceptions) redirected + * back to the page they came from, where they should see a fresh, unpopulated + * copy of the form. * * Here is an example of how to set up a form to redirect to the path 'node': * @code @@ -1279,12 +1297,11 @@ function drupal_validate_form($form_id, &$form, &$form_state) { * form builder functions or form validation/submit handlers. * - If $form_state['redirect'] is set to FALSE, redirection is disabled. * - If none of the above conditions has prevented redirection, then the - * redirect is accomplished by calling drupal_goto(), passing in the value of - * $form_state['redirect'] if it is set, or the current path if it is - * not. drupal_goto() preferentially uses the value of $_GET['destination'] + * redirect is accomplished by returning a RedirectResponse, passing in the + * value of $form_state['redirect'] if it is set, or the current path if it is + * not. RedirectResponse preferentially uses the value of $_GET['destination'] * (the 'destination' URL query string) if it is present, so this will - * override any values set by $form_state['redirect']. Note that during - * installation, install_goto() is called in place of drupal_goto(). + * override any values set by $form_state['redirect']. * * @param $form_state * An associative array containing the current state of the form. @@ -1305,22 +1322,33 @@ function drupal_redirect_form($form_state) { if (!empty($form_state['no_redirect'])) { return; } - // Only invoke drupal_goto() if redirect value was not set to FALSE. + // Only invoke a redirection if redirect value was not set to FALSE. if (!isset($form_state['redirect']) || $form_state['redirect'] !== FALSE) { if (isset($form_state['redirect'])) { if (is_array($form_state['redirect'])) { - call_user_func_array('drupal_goto', $form_state['redirect']); + $options = isset($form_state['redirect'][1]) ? $form_state['redirect'][1] : array(); + // Redirections should always use absolute URLs. + $options['absolute'] = TRUE; + $status_code = isset($form_state['redirect'][2]) ? $form_state['redirect'][2] : 302; + return new RedirectResponse(url($form_state['redirect'][0], $options), $status_code); } else { // This function can be called from the installer, which guarantees // that $redirect will always be a string, so catch that case here // and use the appropriate redirect function. - $function = drupal_installation_attempted() ? 'install_goto' : 'drupal_goto'; - $function($form_state['redirect']); + if (drupal_installation_attempted()) { + install_goto($form_state['redirect']); + } + else { + return new RedirectResponse(url($form_state['redirect'], array('absolute' => TRUE))); + } } } - $request = Drupal::request(); - drupal_goto($request->attributes->get('system_path'), array('query' => $request->query->all())); + $url = url(Drupal::request()->attributes->get('system_path'), array( + 'query' => Drupal::request()->query->all(), + 'absolute' => TRUE, + )); + return new RedirectResponse($url); } } @@ -4854,6 +4882,26 @@ function _form_set_attributes(&$element, $class = array()) { } /** + * If you ever use this directly dwarf ninjas will visit you in your sleep and shave the shit out of you. + * + * @param \Symfony\Component\HttpFoundation\Response $response + * A response object. + */ +function _drupal_form_send_response(Response $response) { + $request = Drupal::request(); + $kernel = Drupal::service('http_kernel'); + $event = new FilterResponseEvent($kernel, $request, $kernel::MASTER_REQUEST, $response); + + Drupal::service('event_dispatcher')->dispatch(KernelEvents::RESPONSE, $event); + // Prepare and send the response. + $event->getResponse() + ->prepare($request) + ->send(); + $kernel->terminate($request, $response); + exit; +} + +/** * @} End of "defgroup form_api". */ @@ -5077,9 +5125,6 @@ function batch_set($batch_definition) { /** * Processes the batch. * - * Unless the batch has been marked with 'progressive' = FALSE, the function - * issues a drupal_goto and thus ends page execution. - * * This function is generally not needed in form submit handlers; * Form API takes care of batches that were set during form submission. * @@ -5090,11 +5135,12 @@ function batch_set($batch_definition) { * URL of the batch processing page. * @param $redirect_callback * (optional) Specify a function to be called to redirect to the progressive - * processing page. By default drupal_goto() will be used to redirect to a - * page which will do the progressive page. Specifying another function will - * allow the progressive processing to be processed differently. + * processing page. + * + * @return \Symfony\Component\HttpFoundation\RedirectResponse|null + * A redirect response if the batch is progressive. No return value otherwise. */ -function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = 'drupal_goto') { +function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = NULL) { $batch =& batch_get(); drupal_theme_initialize(); @@ -5135,8 +5181,8 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = 'd $t = get_t(); $batch['error_message'] = $t('Please continue to the error page', array('@error_url' => url($url, array('query' => array('id' => $batch['id'], 'op' => 'finished'))))); - // Clear the way for the drupal_goto() redirection to the batch processing - // page, by saving and unsetting the 'destination', if there is any. + // Clear the way for the redirection to the batch processing page, by + // saving and unsetting the 'destination', if there is any. if (isset($_GET['destination'])) { $batch['destination'] = $_GET['destination']; unset($_GET['destination']); @@ -5149,8 +5195,14 @@ function batch_process($redirect = NULL, $url = 'batch', $redirect_callback = 'd $_SESSION['batches'][$batch['id']] = TRUE; // Redirect for processing. - $function = $batch['redirect_callback']; - $function($batch['url'], array('query' => array('op' => 'start', 'id' => $batch['id']))); + $options = array('query' => array('op' => 'start', 'id' => $batch['id'])); + if (($function = $batch['redirect_callback']) && function_exists($function)) { + $function($batch['url'], $options); + } + else { + $options['absolute'] = TRUE; + return new RedirectResponse(url($batch['url'], $options)); + } } else { // Non-progressive execution: bypass the whole progressbar workflow diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index f798392..708461d 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -618,7 +618,14 @@ function install_run_task($task, &$install_state) { } // Process the batch. For progressive batches, this will redirect. // Otherwise, the batch will complete. - batch_process(install_redirect_url($install_state), install_full_redirect_url($install_state)); + $response = batch_process(install_redirect_url($install_state), install_full_redirect_url($install_state)); + if ($response instanceof Response) { + // Save $_SESSION data from batch. + drupal_session_commit(); + // Send the response. + $response->send(); + exit; + } } // If we are in the middle of processing this batch, keep sending back // any output from the batch process, until the task is complete. diff --git a/core/includes/update.inc b/core/includes/update.inc index 327dce2..bd83cd7 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -871,7 +871,7 @@ function update_batch($start, $redirect = NULL, $url = NULL, $batch = array(), $ 'file' => 'core/includes/update.inc', ); batch_set($batch); - batch_process($redirect, $url, $redirect_callback); + return batch_process($redirect, $url, $redirect_callback); } /** diff --git a/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php new file mode 100644 index 0000000..2410e61 --- /dev/null +++ b/core/lib/Drupal/Core/EventSubscriber/RedirectResponseSubscriber.php @@ -0,0 +1,63 @@ +getResponse(); + if ($response instanceOf RedirectResponse) { + $options = array(); + + $redirect_path = $response->getTargetUrl(); + $destination = $event->getRequest()->query->get('destination'); + // A destination in $_GET always overrides the current RedirectResponse. + // We do not allow absolute URLs to be passed via $_GET, as this can be an + // attack vector, with the following exception: + // - Absolute URLs that point to this site (i.e. same base URL and + // base path) are allowed. + if ($destination && (!url_is_external($destination) || _external_url_is_local($destination))) { + $destination = drupal_parse_url($destination); + + $path = $destination['path']; + $options['query'] = $destination['query']; + $options['fragment'] = $destination['fragment']; + // The 'Location' HTTP header must always be absolute. + $options['absolute'] = TRUE; + + $response->setTargetUrl(url($path, $options)); + } + } + } + + /** + * 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('checkRedirectUrl'); + return $events; + } +} diff --git a/core/modules/action/lib/Drupal/action/Plugin/Action/GotoAction.php b/core/modules/action/lib/Drupal/action/Plugin/Action/GotoAction.php index aff20b0..54b679a 100644 --- a/core/modules/action/lib/Drupal/action/Plugin/Action/GotoAction.php +++ b/core/modules/action/lib/Drupal/action/Plugin/Action/GotoAction.php @@ -10,6 +10,10 @@ use Drupal\Core\Annotation\Action; use Drupal\Core\Annotation\Translation; use Drupal\Core\Action\ConfigurableActionBase; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpKernel\KernelEvents; /** * Redirects to a different URL. @@ -23,10 +27,48 @@ class GotoAction extends ConfigurableActionBase { /** + * The event dispatcher service. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $dispatcher; + + /** + * Constructs a new DeleteNode object. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin ID for the plugin instance. + * @param array $plugin_definition + * The plugin implementation definition. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $dispatcher + * The tempstore factory. + */ + public function __construct(array $configuration, $plugin_id, array $plugin_definition, EventDispatcherInterface $dispatcher) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + + $this->dispatcher = $dispatcher; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) { + return new static($configuration, $plugin_id, $plugin_definition, $container->get('event_dispatcher')); + } + + /** * {@inheritdoc} */ public function execute($object = NULL) { - drupal_goto($this->configuration['url']); + $url = url($this->configuration['url'], array('absolute' => TRUE)); + $response = new RedirectResponse($url); + $listener = function($event) use ($response) { + $event->setResponse($response); + }; + // Add the listener to the event dispatcher. + $this->dispatcher->addListener(KernelEvents::RESPONSE, $listener); } /** diff --git a/core/modules/aggregator/tests/modules/aggregator_test/aggregator_test.module b/core/modules/aggregator/tests/modules/aggregator_test/aggregator_test.module index b18f87b..4427a3a 100644 --- a/core/modules/aggregator/tests/modules/aggregator_test/aggregator_test.module +++ b/core/modules/aggregator/tests/modules/aggregator_test/aggregator_test.module @@ -1,6 +1,7 @@ TRUE)), 301); } diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc index 3890a1a..b2a13a1 100644 --- a/core/modules/comment/comment.admin.inc +++ b/core/modules/comment/comment.admin.inc @@ -6,6 +6,7 @@ */ use Drupal\comment\Plugin\Core\Entity\Comment; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -238,7 +239,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(url('admin/content/comment', array('absolute' => TRUE))); } else { return confirm_form($form, diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc index 5e1b190..2fbcb58 100644 --- a/core/modules/comment/comment.pages.inc +++ b/core/modules/comment/comment.pages.inc @@ -7,6 +7,7 @@ use Drupal\Core\Entity\EntityInterface; use Drupal\comment\Plugin\Core\Entity\Comment; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** @@ -47,7 +48,7 @@ function comment_reply(EntityInterface $node, $pid = NULL) { } else { drupal_set_message(t('You are not authorized to post comments.'), 'error'); - drupal_goto("node/$node->nid"); + return new RedirectResponse(url("node/$node->nid", array('absolute' => TRUE))); } } else { @@ -62,19 +63,19 @@ function comment_reply(EntityInterface $node, $pid = NULL) { if ($comment->nid->target_id != $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(url("node/$node->nid", array('absolute' => TRUE))); } // Display the parent comment $build['comment_parent'] = comment_view($comment); } else { drupal_set_message(t('The comment you are replying to does not exist.'), 'error'); - drupal_goto("node/$node->nid"); + return new RedirectResponse(url("node/$node->nid", array('absolute' => TRUE))); } } else { drupal_set_message(t('You are not authorized to view comments.'), 'error'); - drupal_goto("node/$node->nid"); + return new RedirectResponse(url("node/$node->nid", array('absolute' => TRUE))); } } // This is the case where the comment is in response to a node. Display the node. @@ -85,14 +86,14 @@ function comment_reply(EntityInterface $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(url("node/$node->nid", array('absolute' => TRUE))); } 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(url("node/$node->nid", array('absolute' => TRUE))); } } @@ -120,5 +121,5 @@ function comment_approve(Comment $comment) { $comment->save(); drupal_set_message(t('Comment approved.')); - drupal_goto('node/' . $comment->nid->target_id); + return new RedirectResponse('node/' . $comment->nid->target_id, array('absolute' => TRUE)); } diff --git a/core/modules/image/image.admin.inc b/core/modules/image/image.admin.inc index 59cc1c6..935df53 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. */ @@ -284,7 +286,7 @@ function image_effect_form($form, &$form_state, $style, $effect) { // If there's no configuration for this image effect, return to // the image style page. if (!isset($effect['form callback'])) { - drupal_goto('admin/config/media/image-styles/manage/' . $style->id()); + return new RedirectResponse(url('admin/config/media/image-styles/manage/' . $style->id(), array('absolute' => TRUE))); } $form_state['image_style'] = $style; $form_state['image_effect'] = $effect; diff --git a/core/modules/language/language.admin.inc b/core/modules/language/language.admin.inc index e41f6bc..ee3dbd1 100644 --- a/core/modules/language/language.admin.inc +++ b/core/modules/language/language.admin.inc @@ -7,6 +7,7 @@ use Drupal\Core\Language\Language; use Drupal\Core\Language\LanguageManager; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -298,7 +299,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(url('admin/config/regional/language', array('absolute' => TRUE))); } // For other languages, warn the user that data loss is ahead. diff --git a/core/modules/locale/locale.pages.inc b/core/modules/locale/locale.pages.inc index 766f6e9..926fc08 100644 --- a/core/modules/locale/locale.pages.inc +++ b/core/modules/locale/locale.pages.inc @@ -8,6 +8,7 @@ use Drupal\Core\Language\Language; use Drupal\locale\SourceString; use Drupal\locale\TranslationString; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -479,9 +480,9 @@ function locale_translation_manual_status() { // Execute a batch if required. A batch is only used when remote files // are checked. if (batch_get()) { - batch_process('admin/reports/translations'); + return batch_process('admin/reports/translations'); } - drupal_goto('admin/reports/translations'); + return new RedirectResponse(url('admin/reports/translations', array('absolute' => TRUE))); } /** diff --git a/core/modules/node/lib/Drupal/node/Form/DeleteMultiple.php b/core/modules/node/lib/Drupal/node/Form/DeleteMultiple.php index c47c683..a774c49 100644 --- a/core/modules/node/lib/Drupal/node/Form/DeleteMultiple.php +++ b/core/modules/node/lib/Drupal/node/Form/DeleteMultiple.php @@ -12,6 +12,7 @@ use Drupal\Core\Entity\EntityManager; use Drupal\Component\Utility\String; use Drupal\user\TempStoreFactory; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -97,7 +98,7 @@ protected function getConfirmText() { public function buildForm(array $form, array &$form_state) { $this->nodes = $this->tempStoreFactory->get('node_multiple_delete_confirm')->get($GLOBALS['user']->uid); if (empty($this->nodes)) { - drupal_goto($this->getCancelPath()); + return new RedirectResponse(url($this->getCancelPath(), array('absolute' => TRUE))); } $form['nodes'] = array( diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc index 8255df5..77adfb2 100644 --- a/core/modules/node/node.pages.inc +++ b/core/modules/node/node.pages.inc @@ -10,6 +10,7 @@ */ use Drupal\Core\Entity\EntityInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; /** * Page callback: Displays add content links for available content types. @@ -34,7 +35,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(url('node/add/' . $type->type, array('absolute' => TRUE))); } return array('#theme' => 'node_add_list', '#content' => $content); } diff --git a/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php b/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php index b6c380e..4b938e8 100644 --- a/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php +++ b/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php @@ -134,6 +134,32 @@ public function onResponse(FilterResponseEvent $event) { } } } + $response = $event->getResponse(); + if ($response instanceOf RedirectResponse) { + $path = $response->getTargetUrl(); + // The authorize.php script bootstraps Drupal to a very low level, where + // the PHP code that is necessary to close the overlay properly will not + // be loaded. Therefore, if we are redirecting to authorize.php inside + // the overlay, instead redirect back to the current page with + // instructions to close the overlay there before redirecting to the + // final destination. + $options = array('absolute' => TRUE); + if ($path == system_authorized_get_url($options) || $path == system_authorized_batch_processing_url($options)) { + $_SESSION['overlay_close_dialog'] = array($path, $options); + $path = current_path(); + $options = drupal_get_query_parameters(); + } + + // If the current page request is inside the overlay, add ?render=overlay + // to the new path, so that it appears correctly inside the overlay. + if (isset($options['query'])) { + $options['query'] += array('render' => 'overlay'); + } + else { + $options['query'] = array('render' => 'overlay'); + } + $response->setTargetUrl(url($path, $options)); + } } } diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module index ed88264..d95040c 100644 --- a/core/modules/overlay/overlay.module +++ b/core/modules/overlay/overlay.module @@ -5,6 +5,7 @@ * Displays the Drupal administration interface in an overlay. */ +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Drupal\block\Plugin\Core\Entity\Block; @@ -177,34 +178,6 @@ function overlay_library_info() { } /** - * Implements hook_drupal_goto_alter(). - */ -function overlay_drupal_goto_alter(&$path, &$options, &$http_response_code) { - if (overlay_get_mode() == 'child') { - // The authorize.php script bootstraps Drupal to a very low level, where - // the PHP code that is necessary to close the overlay properly will not be - // loaded. Therefore, if we are redirecting to authorize.php inside the - // overlay, instead redirect back to the current page with instructions to - // close the overlay there before redirecting to the final destination; see - // overlay_init(). - if ($path == system_authorized_get_url() || $path == system_authorized_batch_processing_url()) { - $_SESSION['overlay_close_dialog'] = array($path, $options); - $path = current_path(); - $options = drupal_get_query_parameters(); - } - - // If the current page request is inside the overlay, add ?render=overlay - // to the new path, so that it appears correctly inside the overlay. - if (isset($options['query'])) { - $options['query'] += array('render' => 'overlay'); - } - else { - $options['query'] = array('render' => 'overlay'); - } - } -} - -/** * Implements hook_batch_alter(). * * If the current page request is inside the overlay, add ?render=overlay to @@ -293,7 +266,7 @@ function overlay_user_dismiss_message() { drupal_container()->get('user.data')->set('overlay', $user->uid, 'message_dismissed', 1); 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(url('user/' . $user->uid . '/edit', array('absolute' => TRUE))); } /** diff --git a/core/modules/search/search.pages.inc b/core/modules/search/search.pages.inc index aed41f6..646028a 100644 --- a/core/modules/search/search.pages.inc +++ b/core/modules/search/search.pages.inc @@ -6,6 +6,7 @@ */ use Drupal\Core\Language\Language; +use Symfony\Component\HttpFoundation\RedirectResponse; /** * Page callback: Presents the search form and/or search results. @@ -41,7 +42,7 @@ function search_view($module = NULL, $keys = '') { if ($keys) { $path .= '/' . $keys; } - drupal_goto($path); + return new RedirectResponse(url($path, array('absolute' => TRUE))); } // Default results output is an empty string. diff --git a/core/modules/shortcut/shortcut.admin.inc b/core/modules/shortcut/shortcut.admin.inc index e8ab3b5..a0f59e6 100644 --- a/core/modules/shortcut/shortcut.admin.inc +++ b/core/modules/shortcut/shortcut.admin.inc @@ -5,6 +5,7 @@ * Administrative page callbacks for the shortcut module. */ +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** @@ -498,7 +499,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(url('', array('absolute' => TRUE))); } throw new AccessDeniedHttpException(); diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php b/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php index 50ee959..35c0ce6 100644 --- a/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php +++ b/core/modules/simpletest/lib/Drupal/simpletest/Form/SimpletestResultsForm.php @@ -11,6 +11,7 @@ use Drupal\Core\Database\Connection; use Drupal\Core\Form\FormInterface; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; /** * Test results form for $test_id. @@ -91,9 +92,7 @@ public function buildForm(array $form, array &$form_state, $test_id = NULL) { if (is_numeric($test_id) && !$results = $this->getResults($test_id)) { drupal_set_message(t('No test results to display.'), 'error'); - drupal_goto('admin/config/development/testing'); - - return $form; + return new RedirectResponse(url('admin/config/development/testing', array('absolute' => TRUE))); } // Load all classes and include CSS. diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/GotoTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/GotoTest.php deleted file mode 100644 index c9e3cfc..0000000 --- a/core/modules/system/lib/Drupal/system/Tests/Common/GotoTest.php +++ /dev/null @@ -1,97 +0,0 @@ - 'Redirect functionality', - 'description' => 'Tests the drupal_goto() and hook_drupal_goto_alter() functionality.', - 'group' => 'Common', - ); - } - - /** - * Tests drupal_goto(). - */ - function testDrupalGoto() { - $this->drupalGet('common-test/drupal_goto/redirect'); - $headers = $this->drupalGetHeaders(TRUE); - list(, $status) = explode(' ', $headers[0][':status'], 3); - $this->assertEqual($status, 302, 'Expected response code was sent.'); - $this->assertText('drupal_goto', 'Drupal goto redirect succeeded.'); - $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('absolute' => TRUE)), 'Drupal goto redirected to expected URL.'); - - $this->drupalGet('common-test/drupal_goto/redirect_advanced'); - $headers = $this->drupalGetHeaders(TRUE); - list(, $status) = explode(' ', $headers[0][':status'], 3); - $this->assertEqual($status, 301, 'Expected response code was sent.'); - $this->assertText('drupal_goto', 'Drupal goto redirect succeeded.'); - $this->assertEqual($this->getUrl(), url('common-test/drupal_goto', array('query' => array('foo' => '123'), 'absolute' => TRUE)), 'Drupal goto redirected to expected URL.'); - - // Test that drupal_goto() respects ?destination=xxx. Use a complicated URL - // to test that the path is encoded and decoded properly. - $destination = 'common-test/drupal_goto/destination?foo=%2525&bar=123'; - $this->drupalGet('common-test/drupal_goto/redirect', array('query' => array('destination' => $destination))); - $this->assertText('drupal_goto', 'Drupal goto redirect with destination succeeded.'); - $this->assertEqual($this->getUrl(), url('common-test/drupal_goto/destination', array('query' => array('foo' => '%25', 'bar' => '123'), 'absolute' => TRUE)), 'Drupal goto redirected to given query string destination.'); - - // Test that drupal_goto() respects ?destination=xxx with an absolute URL - // that points to this Drupal installation. - $destination = url('common-test/drupal_goto/alternative', array('absolute' => TRUE)); - $this->drupalGet('common-test/drupal_goto/redirect', array('query' => array('destination' => $destination))); - $this->assertText('drupal_goto_alternative', 'Drupal goto redirect with absolute URL destination that points to this Drupal installation succeeded.'); - $this->assertEqual($this->getUrl(), url('common-test/drupal_goto/alternative', array('absolute' => TRUE)), 'Drupal goto redirected to given query string destination with absolute URL that points to this Drupal installation.'); - - // Test that drupal_goto() fails to respect ?destination=xxx with an absolute URL - // that does not point to this Drupal installation. - $destination = 'http://example.com'; - $this->drupalGet('common-test/drupal_goto/redirect', array('query' => array('destination' => $destination))); - $this->assertText('drupal_goto', 'Drupal goto fails to redirect with absolute URL destination that does not point to this Drupal installation.'); - $this->assertNotEqual($this->getUrl(), $destination, 'Drupal goto failed to redirect to given query string destination with absolute URL that does not point to this Drupal installation.'); - } - - /** - * Tests hook_drupal_goto_alter(). - */ - function testDrupalGotoAlter() { - $this->drupalGet('common-test/drupal_goto/redirect_fail'); - - $this->assertNoText(t("Drupal goto failed to stop program"), 'Drupal goto stopped program.'); - $this->assertNoText('drupal_goto_fail', 'Drupal goto redirect failed.'); - } - - /** - * Tests drupal_get_destination(). - */ - function testDrupalGetDestination() { - $query = $this->randomName(10); - - // Verify that a 'destination' query string is used as destination. - $this->drupalGet('common-test/destination', array('query' => array('destination' => $query))); - $this->assertText('The destination: ' . $query, 'The given query string destination is determined as destination.'); - - // Verify that the current path is used as destination. - $this->drupalGet('common-test/destination', array('query' => array($query => NULL))); - $url = 'common-test/destination?' . $query; - $this->assertText('The destination: ' . $url, 'The current path is determined as destination.'); - } -} diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index 1cfea0c..abfc932 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -8,6 +8,7 @@ use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\ReplaceCommand; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Drupal\Core\Datetime\DrupalDateTime; @@ -299,7 +300,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(url('admin/appearance', array('absolute' => TRUE))); } throw new AccessDeniedHttpException(); } @@ -1223,7 +1224,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(url('admin/modules/uninstall', array('absolute' => TRUE))); } } diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php index 89bbde0..32a7498 100644 --- a/core/modules/system/system.api.php +++ b/core/modules/system/system.api.php @@ -3008,22 +3008,6 @@ function hook_install_tasks(&$install_state) { } /** - * Change the page the user is sent to by drupal_goto(). - * - * @param $path - * A Drupal path or a full URL. - * @param $options - * An associative array of additional URL options to pass to url(). - * @param $http_response_code - * The HTTP status code to use for the redirection. See drupal_goto() for more - * information. - */ -function hook_drupal_goto_alter(&$path, &$options, &$http_response_code) { - // A good addition to misery module. - $http_response_code = 500; -} - -/** * Alter XHTML HEAD tags before they are rendered by drupal_get_html_head(). * * Elements available to be altered are only those added using diff --git a/core/modules/system/system.module b/core/modules/system/system.module index 6a1f766..7e91d75 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -12,6 +12,7 @@ use Drupal\Core\TypedData\Primitive; use Drupal\system\Plugin\Block\SystemMenuBlock; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; use Guzzle\Http\Exception\BadResponseException; use Guzzle\Http\Exception\RequestException; @@ -2330,7 +2331,7 @@ 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 + * submit handler, since calling redirecting 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 @@ -2358,7 +2359,7 @@ function _system_themes_access($theme) { * not to assume any code exists. Example (system_authorized_run()): * @code * system_authorized_init($callback, $file, $arguments, $page_title); - * drupal_goto(system_authorized_get_url()); + * return new RedirectResponse(system_authorized_get_url()); * @endcode * Example (update_manager_install_form_submit()): * @code @@ -2419,9 +2420,13 @@ function system_authorized_get_url(array $options = array()) { /** * Returns the URL for the authorize.php script when it is processing a batch. + * + * @param array $options + * Optional array of options to pass to url(). */ -function system_authorized_batch_processing_url() { - return system_authorized_get_url(array('query' => array('batch' => '1'))); +function system_authorized_batch_processing_url(array $options = array()) { + $options['query'] = array('batch' => '1'); + return system_authorized_get_url($options); } /** @@ -2431,7 +2436,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()); } /** @@ -2442,7 +2447,7 @@ function system_authorized_run($callback, $file, $arguments = array(), $page_tit function system_authorized_batch_process() { $finish_url = system_authorized_get_url(); $process_url = system_authorized_batch_processing_url(); - batch_process($finish_url, $process_url); + return batch_process($finish_url, $process_url); } /** @@ -3353,7 +3358,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(url('', array('absolute' => TRUE))); } /** diff --git a/core/modules/system/tests/modules/batch_test/batch_test.module b/core/modules/system/tests/modules/batch_test/batch_test.module index 85ee47c..2c1bee2 100644 --- a/core/modules/system/tests/modules/batch_test/batch_test.module +++ b/core/modules/system/tests/modules/batch_test/batch_test.module @@ -294,7 +294,7 @@ function batch_test_nested_drupal_form_submit($value = 1) { array('_batch_test_nested_drupal_form_submit_callback', array($value)), ); batch_set($batch); - batch_process('batch-test/redirect'); + return batch_process('batch-test/redirect'); } /** @@ -338,7 +338,7 @@ function batch_test_no_form() { batch_test_stack(NULL, TRUE); batch_set(_batch_test_batch_1()); - batch_process('batch-test/redirect'); + return batch_process('batch-test/redirect'); } /** @@ -348,7 +348,7 @@ function batch_test_large_percentage() { batch_test_stack(NULL, TRUE); batch_set(_batch_test_batch_5()); - batch_process('batch-test/redirect'); + return batch_process('batch-test/redirect'); } /** @@ -506,7 +506,7 @@ function batch_test_theme_batch() { ), ); batch_set($batch); - batch_process('batch-test/redirect'); + return batch_process('batch-test/redirect'); } /** 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 febfd3a..a461a89 100644 --- a/core/modules/system/tests/modules/common_test/common_test.module +++ b/core/modules/system/tests/modules/common_test/common_test.module @@ -9,43 +9,6 @@ * Implements hook_menu(). */ function common_test_menu() { - $items['common-test/drupal_goto'] = array( - 'title' => 'Drupal Goto', - 'page callback' => 'common_test_drupal_goto_land', - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - ); - $items['common-test/drupal_goto/alternative'] = array( - 'title' => 'Drupal Goto', - 'page callback' => 'common_test_drupal_goto_land_alternative', - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - ); - $items['common-test/drupal_goto/fail'] = array( - 'title' => 'Drupal Goto', - 'page callback' => 'common_test_drupal_goto_land_fail', - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - ); - $items['common-test/drupal_goto/redirect'] = array( - 'title' => 'Drupal Goto', - 'page callback' => 'common_test_drupal_goto_redirect', - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - ); - $items['common-test/drupal_goto/redirect_advanced'] = array( - 'title' => 'Drupal Goto', - 'page callback' => 'common_test_drupal_goto_redirect_advanced', - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - ); - $items['common-test/drupal_goto/redirect_fail'] = array( - 'title' => 'Drupal Goto Failure', - 'page callback' => 'drupal_goto', - 'page arguments' => array('common-test/drupal_goto/fail'), - 'access arguments' => array('access content'), - 'type' => MENU_CALLBACK, - ); $items['common-test/destination'] = array( 'title' => 'Drupal Get Destination', 'page callback' => 'common_test_destination', @@ -68,56 +31,6 @@ function common_test_menu() { } /** - * Redirects using drupal_goto(). - */ -function common_test_drupal_goto_redirect() { - drupal_goto('common-test/drupal_goto'); -} - -/** - * Redirects using drupal_goto(). - */ -function common_test_drupal_goto_redirect_advanced() { - drupal_goto('common-test/drupal_goto', array('query' => array('foo' => '123')), 301); -} - -/** - * Page callback: Provides a landing page for drupal_goto(). - * - * @see common_test_menu() - */ -function common_test_drupal_goto_land() { - print "drupal_goto"; -} - -/** - * Page callback: Provides a landing page for drupal_goto(). - * - * @see common_test_menu() - */ -function common_test_drupal_goto_land_alternative() { - print "drupal_goto_alternative"; -} - -/** - * Page callback: Provides a failure landing page for drupal_goto(). - * - * @see common_test_menu() - */ -function common_test_drupal_goto_land_fail() { - print "drupal_goto_fail"; -} - -/** - * Implements hook_drupal_goto_alter(). - */ -function common_test_drupal_goto_alter(&$path, &$options, &$http_response_code) { - if ($path == 'common-test/drupal_goto/fail') { - $path = 'common-test/drupal_goto/redirect'; - } -} - -/** * Prints a destination query parameter. */ function common_test_destination() { diff --git a/core/modules/system/tests/modules/form_test/form_test.module b/core/modules/system/tests/modules/form_test/form_test.module index b73006e..42b1a16 100644 --- a/core/modules/system/tests/modules/form_test/form_test.module +++ b/core/modules/system/tests/modules/form_test/form_test.module @@ -387,6 +387,7 @@ function _form_test_submit_values_json($form, &$form_state) { $response = new JsonResponse($form_state['values']); // @todo remove once converted to new routing system. $response->send(); + exit; } /** diff --git a/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php b/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php index c9f1b0a..91f56f6 100644 --- a/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php +++ b/core/modules/system/tests/modules/session_test/lib/Drupal/session_test/EventSubscriber/SessionTestSubscriber.php @@ -7,10 +7,11 @@ namespace Drupal\session_test\EventSubscriber; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** * Defines a test session subscriber that checks whether the session is empty. @@ -33,13 +34,27 @@ public function onKernelRequestSessionTest(GetResponseEvent $event) { } /** - * Set header for session testing. + * Performs tasks for session_test module on kernel.response. * * @param \Symfony\Component\HttpKernel\Event\FilterResponseEvent $event * The Event to process. */ public function onKernelResponseSessionTest(FilterResponseEvent $event) { - $event->getResponse()->headers->set('X-Session-Empty', $this->emptySession); + $response = $event->getResponse(); + if ($response instanceOf RedirectResponse) { + // Force the redirection to go to a non-secure page after being on a + // secure page through https.php. + global $base_insecure_url, $is_https_mock; + // Alter the redirect to use HTTP when using a mock HTTPS request through + // https.php because form submissions would otherwise redirect to a + // non-existent HTTPS site. + if (!empty($is_https_mock)) { + $path = $base_insecure_url . '/' . $path; + $response->setTargetUrl($path); + } + } + // Set header for session testing. + $response->headers->set('X-Session-Empty', $this->emptySession); } /** diff --git a/core/modules/system/tests/modules/session_test/session_test.module b/core/modules/system/tests/modules/session_test/session_test.module index b3e82fd..73bf3ff 100644 --- a/core/modules/system/tests/modules/session_test/session_test.module +++ b/core/modules/system/tests/modules/session_test/session_test.module @@ -162,22 +162,6 @@ function session_test_form_user_login_form_alter(&$form) { } /** - * Implements hook_drupal_goto_alter(). - * - * 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(&$path, &$options, &$http_response_code) { - global $base_insecure_url, $is_https_mock; - // Alter the redirect to use HTTP when using a mock HTTPS request through - // https.php because form submissions would otherwise redirect to a - // non-existent HTTPS site. - if (!empty($is_https_mock)) { - $path = $base_insecure_url . '/' . $path; - } -} - -/** * Menu callback, only available if current user is logged in. */ function _session_test_is_logged_in() { 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 b73bb5a..ea10a04 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 @@ getEntity(); $source = $form_state['values']['source_langcode']['source']; $path = $this->getBasePath($entity) . '/translations/add/' . $source . '/' . $form_controller->getFormLangcode($form_state); - $form_state['redirect'] = array('path' => $path); + $form_state['redirect'] = $path; $languages = language_list(); drupal_set_message(t('Source language set to: %language', array('%language' => $languages[$source]->name))); } diff --git a/core/modules/update/update.authorize.inc b/core/modules/update/update.authorize.inc index c74a93f..57acc34 100644 --- a/core/modules/update/update.authorize.inc +++ b/core/modules/update/update.authorize.inc @@ -53,7 +53,7 @@ function update_authorize_run_update($filetransfer, $projects) { batch_set($batch); // Invoke the batch via authorize.php. - system_authorized_batch_process(); + return system_authorized_batch_process(); } /** @@ -98,7 +98,7 @@ function update_authorize_run_install($filetransfer, $project, $updater_name, $l batch_set($batch); // Invoke the batch via authorize.php. - system_authorized_batch_process(); + return system_authorized_batch_process(); } /** diff --git a/core/modules/update/update.fetch.inc b/core/modules/update/update.fetch.inc index 96f00f1..131deb7 100644 --- a/core/modules/update/update.fetch.inc +++ b/core/modules/update/update.fetch.inc @@ -28,7 +28,7 @@ function update_manual_status() { 'file' => drupal_get_path('module', 'update') . '/update.fetch.inc', ); batch_set($batch); - batch_process('admin/reports/updates'); + return batch_process('admin/reports/updates'); } /** diff --git a/core/modules/update/update.manager.inc b/core/modules/update/update.manager.inc index bc73db0..8e2bce9 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(url('admin/update/ready', array('absolute' => TRUE))); } else { // Ideally we're catching all Exceptions, so they should never see this, diff --git a/core/modules/user/lib/Drupal/user/Controller/UserController.php b/core/modules/user/lib/Drupal/user/Controller/UserController.php index 864e095..e782019 100644 --- a/core/modules/user/lib/Drupal/user/Controller/UserController.php +++ b/core/modules/user/lib/Drupal/user/Controller/UserController.php @@ -41,9 +41,7 @@ public static function create(ContainerInterface $container) { */ public function logout(Request $request) { user_logout(); - // @todo Remove the destination check once drupal.org/node/1668866 is in. - $url = $request->query->get('destination') ?: ''; - return new RedirectResponse(url($url, array('absolute' => TRUE))); + return new RedirectResponse(url('', array('absolute' => TRUE))); } } diff --git a/core/modules/user/lib/Drupal/user/RegisterFormController.php b/core/modules/user/lib/Drupal/user/RegisterFormController.php index ceecd65..7d22cd3 100644 --- a/core/modules/user/lib/Drupal/user/RegisterFormController.php +++ b/core/modules/user/lib/Drupal/user/RegisterFormController.php @@ -7,6 +7,8 @@ namespace Drupal\user; +use Symfony\Component\HttpFoundation\RedirectResponse; + /** * Form controller for the user register forms. */ @@ -31,7 +33,7 @@ public function form(array $form, array &$form_state) { // 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(url('user/' . $user->uid, array('absolute' => TRUE))); } $form['#attached']['library'][] = array('system', 'jquery.cookie'); diff --git a/core/modules/user/user.module b/core/modules/user/user.module index c60e823..896314a 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -12,6 +12,7 @@ use Drupal\user\UserRole; use Drupal\user\RoleInterface; use Drupal\Core\Template\Attribute; +use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Drupal\menu_link\Plugin\Core\Entity\MenuLink; @@ -2013,7 +2014,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(url('admin/people', array('absolute' => TRUE))); } } diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc index 26fb040..a8559d0 100644 --- a/core/modules/user/user.pages.inc +++ b/core/modules/user/user.pages.inc @@ -112,7 +112,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(url('', array('absolute' => TRUE))); } else { // Time out, in seconds, until login URL expires. @@ -124,7 +124,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(url('user/password', array('absolute' => TRUE))); } 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 @@ -139,7 +139,10 @@ 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 = Crypt::randomStringHashed(55); $_SESSION['pass_reset_' . $user->uid] = $token; - drupal_goto('user/' . $user->uid . '/edit', array('query' => array('pass-reset-token' => $token))); + return new RedirectResponse(url('user/' . $user->uid . '/edit', array( + 'query' => array('pass-reset-token' => $token), + 'absolute' => TRUE, + ))); } else { if (!$account->login) { @@ -158,7 +161,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(url('user/password', array('absolute' => TRUE))); } } else { @@ -389,11 +392,11 @@ function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') { // Since user_cancel() is not invoked via Form API, batch processing needs // to be invoked manually and should redirect to the front page after // completion. - batch_process(''); + return batch_process(''); } 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(url("user/$account->uid/cancel", array('absolute' => TRUE))); } } throw new AccessDeniedHttpException(); diff --git a/core/update.php b/core/update.php index a3dd4bb..b73e3ce 100644 --- a/core/update.php +++ b/core/update.php @@ -512,7 +512,7 @@ function update_check_requirements($skip_warnings = FALSE) { // update.php correctly by default. $batch_url = $base_root . drupal_current_script_url(); $redirect_url = $base_root . drupal_current_script_url(array('op' => 'results')); - update_batch($request->request->get('start'), $redirect_url, $batch_url); + $output = update_batch($request->request->get('start'), $redirect_url, $batch_url); break; }