From 34ba7cc55f1d3e7c1d3a9b0257f6fa7a8d8c4520 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Tue, 11 Jun 2013 22:12:01 +0100
Subject: [PATCH] Issue #1623114 by ParisLiakos, chrisdolby, marvil07: Remove
 drupal_exit().

---
 core/includes/ajax.inc                        |  4 +-
 core/includes/common.inc                      | 24 +++++-------
 core/includes/install.inc                     | 11 ++++--
 core/modules/image/image.module               |  6 +--
 core/modules/locale/locale.bulk.inc           | 11 +++---
 .../EventSubscriber/OverlaySubscriber.php     |  6 ++-
 core/modules/overlay/overlay.module           | 11 ++++--
 .../tests/modules/form_test/form_test.module  |  8 ++--
 core/modules/xmlrpc/xmlrpc.server.inc         | 39 +++++++++++++------
 9 files changed, 71 insertions(+), 49 deletions(-)

diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc
index 42843faeb733..94444f16b030 100644
--- a/core/includes/ajax.inc
+++ b/core/includes/ajax.inc
@@ -5,6 +5,8 @@
  * Functions for use with Drupal's Ajax framework.
  */
 
+use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+
 /**
  * @defgroup ajax Ajax framework
  * @{
@@ -326,7 +328,7 @@ function ajax_get_form() {
     // This is likely a hacking attempt as it never happens under normal
     // circumstances, so we just do nothing.
     watchdog('ajax', 'Invalid form POST data.', array(), WATCHDOG_WARNING);
-    drupal_exit();
+    throw new BadRequestHttpException();
   }
 
   // Since some of the submit handlers are run, redirects need to be disabled.
diff --git a/core/includes/common.inc b/core/includes/common.inc
index fb38812e7864..1e9b54fc7751 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -7,6 +7,7 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Language\Language;
 use Symfony\Component\DependencyInjection\Container;
+use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\Yaml\Parser;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpFoundation\Request;
@@ -702,12 +703,19 @@ function drupal_goto($path = '', array $options = array(), $http_response_code =
   $options['absolute'] = TRUE;
 
   $url = Drupal::urlGenerator()->generateFromPath($path, $options);
-  header('Location: ' . $url, TRUE, $http_response_code);
+
+  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.
-  drupal_exit();
+  exit;
 }
 
 /**
@@ -1580,18 +1588,6 @@ function l($text, $path, array $options = array()) {
   return '<a href="' . $url . '"' . $attributes . '>' . $text . '</a>';
 }
 
-/**
- * Performs end-of-request tasks.
- *
- * There should rarely be a reason to call exit instead of drupal_exit();
- */
-function drupal_exit() {
-  if (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL) {
-    drupal_session_commit();
-  }
-  exit;
-}
-
 /**
  * Forms an associative array from a linear array.
  *
diff --git a/core/includes/install.inc b/core/includes/install.inc
index c2cb7506f1d4..503b3da05c82 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -5,6 +5,7 @@
  * API functions for installing modules and themes.
  */
 
+use Symfony\Component\HttpFoundation\RedirectResponse;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Core\Database\Database;
 use Drupal\Core\DrupalKernel;
@@ -859,10 +860,12 @@ function drupal_install_fix_file($file, $mask, $message = TRUE) {
  */
 function install_goto($path) {
   global $base_url;
-  include_once __DIR__ . '/common.inc';
-  header('Location: ' . $base_url . '/' . $path);
-  header('Cache-Control: no-cache'); // Not a permanent redirect.
-  drupal_exit();
+  $headers = array(
+    // Not a permanent redirect.
+    'Cache-Control' => 'no-cache',
+  );
+  $response = new RedirectResponse($base_url . '/' . $path, 302, $headers);
+  $response->send();
 }
 
 /**
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index 2304c7d1f6de..47b2e2156c3d 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -12,6 +12,7 @@
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpFoundation\BinaryFileResponse;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Uuid\Uuid;
 use Drupal\file\Plugin\Core\Entity\File;
@@ -578,10 +579,7 @@ function image_style_deliver($style, $scheme) {
     if (!$lock_acquired) {
       // Tell client to retry again in 3 seconds. Currently no browsers are known
       // to support Retry-After.
-      drupal_add_http_header('Status', '503 Service Unavailable');
-      drupal_add_http_header('Retry-After', 3);
-      print t('Image generation in progress. Try again shortly.');
-      drupal_exit();
+      throw new ServiceUnavailableHttpException(3, t('Image generation in progress. Try again shortly.'));
     }
   }
 
diff --git a/core/modules/locale/locale.bulk.inc b/core/modules/locale/locale.bulk.inc
index 1f90503f3f83..6f011af4c8f2 100644
--- a/core/modules/locale/locale.bulk.inc
+++ b/core/modules/locale/locale.bulk.inc
@@ -9,7 +9,7 @@
 use Drupal\locale\Gettext;
 use Drupal\locale\PoDatabaseReader;
 use Drupal\Core\Language\Language;
-
+use Symfony\Component\HttpFoundation\BinaryFileResponse;
 
 /**
  * Form constructor for the translation import screen.
@@ -254,10 +254,11 @@ function locale_translate_export_form_submit($form, &$form_state) {
     $writer->writeItems($reader);
     $writer->close();
 
-    header("Content-Disposition: attachment; filename=$filename");
-    header("Content-Type: text/plain; charset=utf-8");
-    print file_get_contents($uri);
-    drupal_exit();
+    $response = new BinaryFileResponse($uri);
+    $response->setContentDisposition('attachment', $filename);
+    // @todo remove lines below once converted to new routing system.
+    $response->prepare(Drupal::request())
+      ->send();
   }
   else {
     drupal_set_message('Nothing to export.');
diff --git a/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php b/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php
index da15be13905d..b6c380ef6d86 100644
--- a/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php
+++ b/core/modules/overlay/lib/Drupal/overlay/EventSubscriber/OverlaySubscriber.php
@@ -83,13 +83,15 @@ public function onRequest(GetResponseEvent $event) {
         // If a previous page requested that we close the overlay, close it and
         // redirect to the final destination.
         if (isset($_SESSION['overlay_close_dialog'])) {
-          call_user_func_array('overlay_close_dialog', $_SESSION['overlay_close_dialog']);
+          $response = call_user_func_array('overlay_close_dialog', $_SESSION['overlay_close_dialog']);
           unset($_SESSION['overlay_close_dialog']);
+          $event->setResponse($response);
         }
         // If this page shouldn't be rendered inside the overlay, redirect to
         // the parent.
         elseif (!path_is_admin($current_path)) {
-          overlay_close_dialog($current_path, array('query' => drupal_get_query_parameters(NULL, array('render'))));
+          $response = overlay_close_dialog($current_path, array('query' => drupal_get_query_parameters(NULL, array('render'))));
+          $event->setResponse($response);
         }
 
         // Indicate that we are viewing an overlay child page.
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 1daf3ed7c49c..ed8826436e37 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -493,11 +493,13 @@ function overlay_preprocess_page(&$variables) {
  * interruption, and also allowing the display of messages to be deferred to
  * the parent window (rather than displaying them in the child window, which
  * will close before the user has had a chance to read them).
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ *   A Response object.
  */
 function overlay_deliver_empty_page() {
   $empty_page = '<html><head><title></title>' . drupal_get_css() . drupal_get_js() . '</head><body class="overlay"></body></html>';
-  print $empty_page;
-  drupal_exit();
+  return new Response($empty_page);
 }
 
 /**
@@ -637,6 +639,9 @@ function overlay_overlay_child_initialize() {
  *   (optional) An associative array of options to use when generating the
  *   redirect URL.
  *
+ * @return \Symfony\Component\HttpFoundation\Response
+ *   A Response object.
+ *
  * @todo This function should only request that the overlay close when the page
  *   is displayed (as it did in Drupal 7), not immediately end the request.
  */
@@ -656,7 +661,7 @@ function overlay_close_dialog($redirect = NULL, $redirect_options = array()) {
 
   // Since we are closing the overlay as soon as the page is displayed, we do
   // not want to show any of the page's actual content.
-  overlay_deliver_empty_page();
+  return overlay_deliver_empty_page();
 }
 
 /**
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 63973aa19cfa..b73006e177ed 100644
--- a/core/modules/system/tests/modules/form_test/form_test.module
+++ b/core/modules/system/tests/modules/form_test/form_test.module
@@ -12,6 +12,7 @@
 use Drupal\form_test\FormTestObject;
 use Drupal\form_test\SystemConfigFormTestForm;
 use Drupal\Core\Datetime\DrupalDateTime;
+use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
  * Implements hook_menu().
@@ -383,10 +384,9 @@ function form_test_permission() {
  * Form submit handler to return form values as JSON.
  */
 function _form_test_submit_values_json($form, &$form_state) {
-  // This won't have a proper JSON header, but Drupal doesn't check for that
-  // anyway so this is fine until it's replaced with a JsonResponse.
-  print drupal_json_encode($form_state['values']);
-  drupal_exit();
+  $response = new JsonResponse($form_state['values']);
+  // @todo remove once converted to new routing system.
+  $response->send();
 }
 
 /**
diff --git a/core/modules/xmlrpc/xmlrpc.server.inc b/core/modules/xmlrpc/xmlrpc.server.inc
index e1c160bfec50..fded0119cc2b 100644
--- a/core/modules/xmlrpc/xmlrpc.server.inc
+++ b/core/modules/xmlrpc/xmlrpc.server.inc
@@ -5,12 +5,18 @@
  * Page callback file for the xmlrpc module.
  */
 
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+
 /**
  * Process an XML-RPC request.
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ *   A Response object.
  */
 function xmlrpc_server_page() {
   module_load_include('inc', 'xmlrpc');
-  xmlrpc_server(module_invoke_all('xmlrpc'));
+  return xmlrpc_server(module_invoke_all('xmlrpc'));
 }
 
 /**
@@ -18,6 +24,9 @@ function xmlrpc_server_page() {
  *
  * @param array $callbacks
  *   Array of external XML-RPC method names with the callbacks they map to.
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ *   A Response object.
  */
 function xmlrpc_server($callbacks) {
   $xmlrpc_server = new stdClass();
@@ -71,15 +80,14 @@ function xmlrpc_server($callbacks) {
 
   $data = file_get_contents('php://input');
   if (!$data) {
-    print 'XML-RPC server accepts POST requests only.';
-    drupal_exit();
+    throw new BadRequestHttpException('XML-RPC server accepts POST requests only.');
   }
   $xmlrpc_server->message = xmlrpc_message($data);
   if (!xmlrpc_message_parse($xmlrpc_server->message)) {
-    xmlrpc_server_error(-32700, t('Parse error. Request not well formed.'));
+    return xmlrpc_server_error(-32700, t('Parse error. Request not well formed.'));
   }
   if ($xmlrpc_server->message->messagetype != 'methodCall') {
-    xmlrpc_server_error(-32600, t('Server error. Invalid XML-RPC. Request must be a methodCall.'));
+    return xmlrpc_server_error(-32600, t('Server error. Invalid XML-RPC. Request must be a methodCall.'));
   }
   if (!isset($xmlrpc_server->message->params)) {
     $xmlrpc_server->message->params = array();
@@ -88,7 +96,7 @@ function xmlrpc_server($callbacks) {
   $result = xmlrpc_server_call($xmlrpc_server, $xmlrpc_server->message->methodname, $xmlrpc_server->message->params);
 
   if (is_object($result) && !empty($result->is_error)) {
-    xmlrpc_server_error($result);
+    return xmlrpc_server_error($result);
   }
   // Encode the result
   $r = xmlrpc_value($result);
@@ -104,7 +112,7 @@ function xmlrpc_server($callbacks) {
 
 ';
   // Send it
-  xmlrpc_server_output($xml);
+  return xmlrpc_server_output($xml);
 }
 
 /**
@@ -115,12 +123,15 @@ function xmlrpc_server($callbacks) {
  * @param $message
  *   (optional) The description of the error. Used only if an integer error
  *   code was passed in.
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ *   A Response object.
  */
 function xmlrpc_server_error($error, $message = FALSE) {
   if ($message && !is_object($error)) {
     $error = xmlrpc_error($error, $message);
   }
-  xmlrpc_server_output(xmlrpc_error_get_xml($error));
+  return xmlrpc_server_output(xmlrpc_error_get_xml($error));
 }
 
 /**
@@ -128,13 +139,17 @@ function xmlrpc_server_error($error, $message = FALSE) {
  *
  * @param string $xml
  *   XML to send to the browser.
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ *   A Response object.
  */
 function xmlrpc_server_output($xml) {
   $xml = '<?xml version="1.0"?>' . "\n" . $xml;
-  drupal_add_http_header('Content-Length', strlen($xml));
-  drupal_add_http_header('Content-Type', 'text/xml');
-  echo $xml;
-  drupal_exit();
+  $headers = array(
+    'Content-Length' => strlen($xml),
+    'Content-Type' => 'text/xml'
+  );
+  return new Response($xml, 200, $headers);
 }
 
 /**
-- 
GitLab