Commit 9c0bfb2d authored by alexpott's avatar alexpott

Issue #2339491 by corbacho, dawehner, larowlan, effulgentsia, webflo: Ajax...

Issue #2339491 by corbacho, dawehner, larowlan, effulgentsia, webflo: Ajax requests on forms with files fail on IE 9
parent 4936e3d6
......@@ -765,6 +765,7 @@ services:
arguments: ['@element_info']
tags:
- { name: render.main_content_renderer, format: drupal_ajax }
- { name: render.main_content_renderer, format: iframeupload }
main_content_renderer.dialog:
class: Drupal\Core\Render\MainContent\DialogRenderer
arguments: ['@title_resolver']
......
......@@ -115,6 +115,42 @@ 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. 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');
// 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
$this->setContent('<textarea>' . $this->data . '</textarea>');
}
}
/**
......
......@@ -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.
*
......
......@@ -23,9 +23,11 @@ class MainContentRenderersPass implements CompilerPassInterface {
*/
public function process(ContainerBuilder $container) {
$main_content_renderers = [];
foreach ($container->findTaggedServiceIds('render.main_content_renderer') as $id => $attributes) {
$format = $attributes[0]['format'];
$main_content_renderers[$format] = $id;
foreach ($container->findTaggedServiceIds('render.main_content_renderer') as $id => $attributes_list) {
foreach ($attributes_list as $attributes) {
$format = $attributes['format'];
$main_content_renderers[$format] = $id;
}
}
$container->setParameter('main_content_renderers', $main_content_renderers);
}
......
......@@ -92,8 +92,7 @@ public function testRead() {
// and hence when there is no matching REST route, the non-REST route is
// used, but it can't render into application/hal+json, so it returns a 406.
$this->assertResponse('406', 'HTTP response code is 406 when the resource does not define formats, because it falls back to the canonical, non-REST route.');
$expected_message = '{"message":"Not Acceptable.","supported_mime_types":["text\\/html","application\\/vnd.drupal-ajax","application\\/vnd.drupal-dialog","application\\/vnd.drupal-modal"]}';
$this->assertIdentical($expected_message, $response);
$this->assertTrue(strpos($response, '{"message":"Not Acceptable.","supported_mime_types":') !== FALSE);
}
/**
......
......@@ -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(), '<textarea>[]</textarea>');
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment