diff --git a/core/lib/Drupal/Core/Ajax/AjaxResponse.php b/core/lib/Drupal/Core/Ajax/AjaxResponse.php
index f69af83..9f05639 100644
--- a/core/lib/Drupal/Core/Ajax/AjaxResponse.php
+++ b/core/lib/Drupal/Core/Ajax/AjaxResponse.php
@@ -78,6 +78,32 @@ public function prepareResponse(Request $request) {
     if ($this->data == '{}') {
       $this->setData($this->ajaxRender($request));
     }
+
+    // IE 9 does not support XHR 2 (http://caniuse.com/#feat=xhr2), so
+    // for that browser, jquery.form submits requests containing a file upload
+    // via an IFRAME rather than via XHR. Since the response is being sent to
+    // an IFRAME, it must be formatted as HTML. Specifically:
+    // - It must use the text/html content type or else the browser will
+    //   present a download prompt.
+    // - It must place the JSON data into a textarea to prevent browser
+    //   extensions such as Linkification and Skype's Browser Highlighter
+    //   from applying HTML transformations such as URL or phone number to
+    //   link conversions on the data values.
+    //
+    // Since this affects the format of the output, it could be argued that
+    // this should be implemented as a separate Accept MIME type. However,
+    // that would require separate variants for each type of AJAX request
+    // (e.g., drupal-ajax, drupal-dialog, drupal-modal), so for expediency,
+    // this browser workaround is implemented via a GET or POST parameter.
+    //
+    // @see http://malsup.com/jquery/form/#file-upload
+    // @see https://drupal.org/node/1009382
+    // @see https://drupal.org/node/2339491
+    // @see Drupal.ajax.prototype.beforeSend()
+    if ($request->get('ajax_iframe_upload', FALSE)) {
+      $this->headers->set('Content-Type', 'text/html; charset=utf-8');
+      $this->setContent('<textarea>' . $this->data  . '</textarea>');
+    }
   }
 
   /**
diff --git a/core/lib/Drupal/Core/ContentNegotiation.php b/core/lib/Drupal/Core/ContentNegotiation.php
index 857f9d5..0fc9d19 100644
--- a/core/lib/Drupal/Core/ContentNegotiation.php
+++ b/core/lib/Drupal/Core/ContentNegotiation.php
@@ -30,11 +30,6 @@ class ContentNegotiation {
    *   The normalized type of a given request.
    */
   public function getContentType(Request $request) {
-    // AJAX iframe uploads need special handling, because they contain a JSON
-    // response wrapped in <textarea>.
-    if ($request->get('ajax_iframe_upload', FALSE)) {
-      return 'iframeupload';
-    }
 
     // Check all formats, if priority format is found return it.
     $first_found_format = FALSE;
diff --git a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
index 0b0c274..0383a37 100644
--- a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php
@@ -91,20 +91,6 @@ public function onJson(GetResponseForControllerResultEvent $event) {
     return $response;
   }
 
-  public function onIframeUpload(GetResponseForControllerResultEvent $event) {
-    $response = $event->getResponse();
-
-    // Browser IFRAMEs expect HTML. Browser extensions, such as Linkification
-    // and Skype's Browser Highlighter, convert URLs, phone numbers, etc. into
-    // links. This corrupts the JSON response. Protect the integrity of the
-    // JSON data by making it the value of a textarea.
-    // @see http://malsup.com/jquery/form/#file-upload
-    // @see http://drupal.org/node/1009382
-    $html = '<textarea>' . $response->getContent() . '</textarea>';
-
-    return new Response($html);
-  }
-
   /**
    * Registers the methods in this class that should be listeners.
    *
