diff --git a/core/lib/Drupal/Core/Ajax/AjaxResponse.php b/core/lib/Drupal/Core/Ajax/AjaxResponse.php index 0ada14e..1bc3d7e 100644 --- a/core/lib/Drupal/Core/Ajax/AjaxResponse.php +++ b/core/lib/Drupal/Core/Ajax/AjaxResponse.php @@ -116,8 +116,30 @@ public function prepareResponse(Request $request) { $this->setData($this->ajaxRender($request)); } - // Add proper HTTP Header for IE. + // 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. Note: This applies to both file uploads + // as well as any ajax request in a form with a file upload form. + // - 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() $accept = $request->headers->get('accept'); + if (strpos($accept, 'text/html') !== FALSE) { $this->headers->set('Content-Type', 'text/html; charset=utf-8'); diff --git a/core/tests/Drupal/Tests/Core/Ajax/AjaxResponseTest.php b/core/tests/Drupal/Tests/Core/Ajax/AjaxResponseTest.php index 0ddb9a4..19bbe8d 100644 --- a/core/tests/Drupal/Tests/Core/Ajax/AjaxResponseTest.php +++ b/core/tests/Drupal/Tests/Core/Ajax/AjaxResponseTest.php @@ -8,7 +8,9 @@ namespace Drupal\Tests\Core\Ajax; use Drupal\Core\Ajax\AjaxResponse; +use Drupal\Core\Render\Element\Ajax; use Drupal\Tests\UnitTestCase; +use Symfony\Component\HttpFoundation\Request; /** * @coversDefaultClass \Drupal\Core\Ajax\AjaxResponse @@ -68,5 +70,21 @@ public function testCommands() { $this->assertSame($commands[0], array('command' => 'three', 'class' => 'test-class')); } + /** + * Tests the support for IE specific headers in file uploads. + * + * @cover ::prepareResponse + */ + public function testPrepareResponseForIeFormRequestsWithFileUpload() { + $request = Request::create('/example', 'POST'); + $request->headers->set('Accept', 'text/html'); + $response = new AjaxResponse([]); + $response->headers->set('Content-Type', 'application/json; charset=utf-8'); + + $response->prepare($request); + $this->assertEquals('text/html; charset=utf-8', $response->headers->get('Content-Type')); + $this->assertEquals($response->getContent(), ''); + } + }