diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 3d41fcb..0918b0c 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -348,8 +348,7 @@ function drupal_environment_initialize() {
     $_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']);
     if (!drupal_valid_http_host($_SERVER['HTTP_HOST'])) {
       // HTTP_HOST is invalid, e.g. if containing slashes it may be an attack.
-      header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
-      exit;
+      return new Response('Bad Request', 400);
     }
   }
   else {
@@ -1365,10 +1364,10 @@ function drupal_handle_request($test_only = FALSE) {
   // autoloader with required namespaces registered.
   drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
 
-  // Exit if we should be in a test environment but aren't.
+  // Make sure this file can only be used by simpletest.
   if ($test_only && !drupal_valid_test_ua()) {
     header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
-    exit;
+    return;
   }
 
   $kernel = new DrupalKernel('prod', drupal_classloader(), !$test_only);
@@ -1563,7 +1562,7 @@ function _drupal_bootstrap_page_cache() {
       // We are done.
       $response->prepare($request);
       $response->send();
-      exit;
+      return;
     }
   }
 }
diff --git a/core/includes/errors.inc b/core/includes/errors.inc
index 8b0b9e4..e5910a6 100644
--- a/core/includes/errors.inc
+++ b/core/includes/errors.inc
@@ -163,7 +163,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
       // When called from CLI, simply output a plain text message.
       // Should not translate the string to avoid errors producing more errors.
       print html_entity_decode(strip_tags(format_string('%type: !message in %function (line %line of %file).', $error))). "\n";
-      exit;
+      return;
     }
   }
 
@@ -174,7 +174,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
         // Should not translate the string to avoid errors producing more errors.
         print format_string('%type: !message in %function (line %line of %file).', $error);
       }
-      exit;
+      return;
     }
   }
   else {
diff --git a/core/modules/system/tests/http.php b/core/modules/system/tests/http.php
index 662031f..19bd0d4 100644
--- a/core/modules/system/tests/http.php
+++ b/core/modules/system/tests/http.php
@@ -20,4 +20,4 @@
 chdir('../../../..');
 require_once dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
 require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc';
-drupal_handle_request(TRUE);
+drupal_handle_request(TRUE);
\ No newline at end of file
diff --git a/core/modules/system/tests/https.php b/core/modules/system/tests/https.php
index 247e6e5..39d48a2 100644
--- a/core/modules/system/tests/https.php
+++ b/core/modules/system/tests/https.php
@@ -22,4 +22,4 @@
 chdir('../../../..');
 require_once dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
 require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc';
-drupal_handle_request(TRUE);
+drupal_handle_request(TRUE);
\ No newline at end of file
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 42ef667..0bfc1ca 100644
--- a/core/modules/system/tests/modules/form_test/form_test.module
+++ b/core/modules/system/tests/modules/form_test/form_test.module
@@ -34,7 +34,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;
+  return;
 }
 
 /**
@@ -763,10 +763,9 @@ function form_test_form_state_values_clean_form($form, &$form_state) {
  */
 function form_test_form_state_values_clean_form_submit($form, &$form_state) {
   form_state_values_clean($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 Json::encode($form_state['values']);
-  exit;
+  $response = new JsonResponse($form_state['values']);
+  $response->send();
+  return FALSE;
 }
 
 /**
@@ -795,7 +794,7 @@ function form_test_form_state_values_clean_advanced_form($form, &$form_state) {
 function form_test_form_state_values_clean_advanced_form_submit($form, &$form_state) {
   form_state_values_clean($form_state);
   print t('You WIN!');
-  exit;
+  return FALSE;
 }
 
 /**
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 c618bab..c113aa6 100644
--- a/core/modules/system/tests/modules/session_test/session_test.module
+++ b/core/modules/system/tests/modules/session_test/session_test.module
@@ -1,13 +1,15 @@
 <?php
 
+use Symfony\Component\HttpFoundation\Response;
+
 /**
  * Implements hook_user_login().
  */
 function session_test_user_login($account) {
   if ($account->getUsername() == 'session_test_user') {
     // Exit so we can verify that the session was regenerated
-    // before hook_user_login() was called.
-    exit;
+    // before hook_user() was called.
+    return new Response('OK', Response::HTTP_OK );
   }
 }
 
diff --git a/core/modules/system/tests/modules/url_alter_test/url_alter_test.module b/core/modules/system/tests/modules/url_alter_test/url_alter_test.module
new file mode 100644
index 0000000..4637454
--- /dev/null
+++ b/core/modules/system/tests/modules/url_alter_test/url_alter_test.module
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Module to help test hook_url_inbound_alter() and hook_url_outbound_alter().
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function url_alter_test_menu() {
+  $items['url-alter-test/foo'] = array(
+    'title' => 'Foo',
+    'page callback' => 'url_alter_test_foo',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+/**
+ * Menu callback.
+ */
+function url_alter_test_foo() {
+  return new Response('current_path=' . current_path() . ' request_path=' . request_path(), 200);
+}
+
+/**
+ * Implements hook_url_inbound_alter().
+ */
+function url_alter_test_url_inbound_alter(&$path, $original_path, $path_language) {
+  if (!request_path() && current_path()) {
+    drupal_set_message("current_path() is non-empty with an empty request path.");
+  }
+
+  // Rewrite user/username to user/uid.
+  if (preg_match('!^user/([^/]+)(/.*)?!', $path, $matches)) {
+    if ($account = user_load_by_name($matches[1])) {
+      $matches += array(2 => '');
+      $path = 'user/' . $account->uid . $matches[2];
+    }
+  }
+
+  // Rewrite community/ to forum/.
+  if ($path == 'community' || strpos($path, 'community/') === 0) {
+    $path = 'forum' . substr($path, 9);
+  }
+
+  if ($path == 'url-alter-test/bar') {
+    $path = 'url-alter-test/foo';
+  }
+}
+
+/**
+ * Implements hook_url_outbound_alter().
+ */
+function url_alter_test_url_outbound_alter(&$path, &$options, $original_path) {
+  // Rewrite user/uid to user/username.
+  if (preg_match('!^user/([0-9]+)(/.*)?!', $path, $matches)) {
+    if ($account = user_load($matches[1])) {
+      $matches += array(2 => '');
+      $path = 'user/' . $account->name . $matches[2];
+    }
+  }
+
+  // Rewrite forum/ to community/.
+  if ($path == 'forum' || strpos($path, 'forum/') === 0) {
+    $path = 'community' . substr($path, 5);
+  }
+}
