diff --git a/core/authorize.php b/core/authorize.php
index 3a34046..da07191 100644
--- a/core/authorize.php
+++ b/core/authorize.php
@@ -22,6 +22,7 @@
 
 use Drupal\Core\DrupalKernel;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 use Drupal\Core\Site\Settings;
 use Drupal\Core\Page\DefaultHtmlPageRenderer;
 
@@ -70,6 +71,7 @@ function authorize_access_allowed() {
 $output = '';
 $show_messages = TRUE;
 
+$response = new Response();
 if (authorize_access_allowed()) {
   // Load both the Form API and Batch API.
   require_once __DIR__ . '/includes/form.inc';
@@ -139,15 +141,16 @@ function authorize_access_allowed() {
   $show_messages = !(($batch = batch_get()) && isset($batch['running']));
 }
 else {
-  drupal_add_http_header('Status', '403 Forbidden');
+  $response->setStatusCode(403);
   \Drupal::logger('access denied')->warning('authorize.php');
   $page_title = t('Access denied');
   $output = t('You are not allowed to access this page.');
 }
 
 if (!empty($output)) {
-  drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
-  print DefaultHtmlPageRenderer::renderPage($output, $page_title, 'maintenance', array(
+  $response->setContent(DefaultHtmlPageRenderer::renderPage($output, $page_title, 'maintenance', array(
     '#show_messages' => $show_messages,
-  ));
+  )));
+  $response->headers->set('Content-Type', 'text/html; charset=utf-8');
+  $response->send();
 }
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 214ce28..6d43a09 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -888,8 +888,6 @@ function install_display_output($output, $install_state) {
   // reached in case of an early installer error.
   drupal_maintenance_theme();
 
-  drupal_page_header();
-
   // Prevent install.php from being indexed when installed in a sub folder.
   // robots.txt rules are not read if the site is within domain.com/subfolder
   // resulting in /subfolder/install.php being found through search engines.
@@ -920,7 +918,16 @@ function install_display_output($output, $install_state) {
     $regions['sidebar_first'] = $task_list;
   }
 
-  print DefaultHtmlPageRenderer::renderPage($output, $output['#title'], 'install', $regions);
+  $response = new Response();
+  $default_headers = array(
+    'Expires' => 'Sun, 19 Nov 1978 05:00:00 GMT',
+    'Last-Modified' => gmdate(DATE_RFC1123, REQUEST_TIME),
+    'Cache-Control' => 'no-cache, must-revalidate, post-check=0, pre-check=0',
+    'ETag' => '"' . REQUEST_TIME . '"',
+  );
+  $response->headers->add($default_headers);
+  $response->setContent(DefaultHtmlPageRenderer::renderPage($output, $output['#title'], 'install', $regions));
+  $response->send();
   exit;
 }
 
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 945ffe7..07a4ca9 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -18,6 +18,7 @@
 use Drupal\Component\Uuid\Uuid;
 use Drupal\Component\Utility\NestedArray;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 
 /**
  * Disables any extensions that are incompatible with the current core version.
@@ -154,8 +155,9 @@ function update_check_requirements($skip_warnings = FALSE) {
     );
     $status_report['#suffix'] = 'Check the messages and <a href="' . check_url(drupal_requirements_url($severity)) . '">try again</a>.';
 
-    drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
-    print DefaultHtmlPageRenderer::renderPage($status_report, 'Requirements problem', 'maintenance', $regions);
+    $response = new Response(DefaultHtmlPageRenderer::renderPage($status_report, 'Requirements problem', 'maintenance', $regions));
+    $response->headers->set('Content-Type', 'text/html; charset=utf-8');
+    $response->send();
     exit();
   }
 }
diff --git a/core/modules/toolbar/src/Controller/ToolbarController.php b/core/modules/toolbar/src/Controller/ToolbarController.php
index 11d17b4..b0ba8fc 100644
--- a/core/modules/toolbar/src/Controller/ToolbarController.php
+++ b/core/modules/toolbar/src/Controller/ToolbarController.php
@@ -23,9 +23,8 @@ class ToolbarController extends ControllerBase {
    * @return \Symfony\Component\HttpFoundation\JsonResponse
    */
   public function subtreesJsonp() {
-    _toolbar_initialize_page_cache();
-    $subtrees = toolbar_get_rendered_subtrees();
-    $response = new JsonResponse($subtrees);
+    $response = _toolbar_initialize_page_cache();
+    $response->setData(toolbar_get_rendered_subtrees());
     $response->setCallback('Drupal.toolbar.setSubtrees.resolve');
     return $response;
   }
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index d8e5363..3ed92ad 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -15,6 +15,7 @@
 use Drupal\menu_link\MenuLinkInterface;
 use Drupal\user\RoleInterface;
 use Drupal\user\UserInterface;
+use Symfony\Component\HttpFoundation\JsonResponse;
 
 /**
  * Implements hook_help().
@@ -116,6 +117,9 @@ function toolbar_element_info() {
  *
  * @todo Replace this hack with something better integrated with DrupalKernel
  *   once Drupal's page caching itself is properly integrated.
+ *
+ * @return \Symfony\Component\HttpFoundation\JsonResponse
+ *   A JSON response object without the actual content.
  */
 function _toolbar_initialize_page_cache() {
   $GLOBALS['conf']['system.performance']['cache']['page']['enabled'] = TRUE;
@@ -141,8 +145,10 @@ function _toolbar_initialize_page_cache() {
   // accesses the callback URL again (e.g., after clearing the browser cache or
   // when force-reloading a Drupal page).
   $max_age = 3600 * 24 * 365;
-  drupal_add_http_header('Expires', gmdate(DateTimePlus::RFC7231, REQUEST_TIME + $max_age));
-  drupal_add_http_header('Cache-Control', 'private, max-age=' . $max_age);
+  $json_response = new JsonResponse();
+  $json_response->headers->set('Expires', gmdate(DateTimePlus::RFC7231, REQUEST_TIME + $max_age));
+  $json_response->headers->set('Cache-Control', 'private, max-age=' . $max_age);
+  return $json_response;
 }
 
 /**
diff --git a/core/update.php b/core/update.php
index 4e8157c..c074d45 100644
--- a/core/update.php
+++ b/core/update.php
@@ -224,8 +224,6 @@ function update_info_page() {
  *   Rendered HTML warning with 403 status.
  */
 function update_access_denied_page() {
-  drupal_add_http_header('Status', '403 Forbidden');
-  header(\Drupal::request()->server->get('SERVER_PROTOCOL') . ' 403 Forbidden');
   \Drupal::logger('access denied')->warning('update.php');
   $output = '<p>Access denied. You are not authorized to access this page. Log in using either an account with the <em>administer software updates</em> permission or the site maintenance account (the account you created during installation). If you cannot log in, you will have to edit <code>settings.php</code> to bypass this access check. To do this:</p>
 <ol>
@@ -349,6 +347,7 @@ function update_task_list($active = NULL) {
 
 $regions = array();
 
+$response = new Response();
 // Only proceed with updates if the user is allowed to run them.
 if (update_access_allowed()) {
 
@@ -409,6 +408,7 @@ function update_task_list($active = NULL) {
 }
 else {
   $output = update_access_denied_page();
+  $response->setStatusCode(403);
 }
 if (isset($output) && $output) {
   // Explicitly start a session so that the update.php token will be accepted.
@@ -419,9 +419,10 @@ function update_task_list($active = NULL) {
     $output->send();
   }
   else {
-    drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
-    print DefaultHtmlPageRenderer::renderPage($output, $output['#title'], 'maintenance', $regions + array(
+    $response->setContent(DefaultHtmlPageRenderer::renderPage($output, $output['#title'], 'maintenance', $regions + array(
       '#show_messages' => !$progress_page,
-    ));
+    )));
+    $response->headers->set('Content-Type', 'text/html; charset=utf-8');
+    $response->send();
   }
 }
