diff --git a/core/lib/Drupal/Core/ContentNegotiation.php b/core/lib/Drupal/Core/ContentNegotiation.php index f1a33d724d232b5e1d4dbdf0465c4ac4b9cb3348..ebab1a82da229a37608ce127d458290239e65aeb 100644 --- a/core/lib/Drupal/Core/ContentNegotiation.php +++ b/core/lib/Drupal/Core/ContentNegotiation.php @@ -12,10 +12,18 @@ class ContentNegotiation { public function getContentType(Request $request) { $acceptable_content_types = $request->getAcceptableContentTypes(); - if (in_array('application/json', $request->getAcceptableContentTypes())) { + if ($request->isXmlHttpRequest()) { + if ($request->get('ajax_iframe_upload', FALSE)) { + return 'iframeupload'; + } + else { + return 'ajax'; + } + } + elseif (in_array('application/json', $request->getAcceptableContentTypes())) { return 'json'; } - if(in_array('text/html', $acceptable_content_types) || in_array('*/*', $acceptable_content_types)) { + elseif(in_array('text/html', $acceptable_content_types) || in_array('*/*', $acceptable_content_types)) { return 'html'; } } diff --git a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php index 8ade061551a526456eaa1e30c9b13165d7063263..2f22f58bf9d75c4d50ba5e8f47d0c1cb6843815b 100644 --- a/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/ViewSubscriber.php @@ -37,6 +37,27 @@ protected function createJsonResponse() { return $response; } + protected function createAjaxResponse(GetResponseEvent $event) { + $response = new Response(); + $response->headers->set('Content-Type', 'application/json; charset=utf-8'); + + return $response; + } + + protected function createIframeUploadResponse(GetResponseEvent $event) { + $response = new Response(); + + // Browsers do not allow JavaScript to read the contents of a user's local + // files. To work around that, the jQuery Form plugin submits forms containing + // a file input element to an IFRAME, instead of using XHR. Browsers do not + // normally expect JSON strings as content within an IFRAME, so the response + // must be customized accordingly. + // @see http://malsup.com/jquery/form/#file-upload + // @see Drupal.ajax.prototype.beforeSend() + $response->headers->set('Content-Type', 'text/html; charset=utf-8'); + + return $response; + } /** * Processes a successful controller into an HTTP 200 response. @@ -75,6 +96,42 @@ public function onJson(GetResponseEvent $event) { return $response; } + public function onAjax(GetResponseEvent $event) { + $page_callback_result = $event->getControllerResult(); + + // Construct the response content from the page callback result. + $commands = ajax_prepare_response($page_callback_result); + $json = ajax_render($commands); + + // Build the actual response object. + $response = $this->createAjaxResponse($event); + $response->setContent($json); + + return $response; + } + + public function onIframeUpload(GetResponseEvent $event) { + $page_callback_result = $event->getControllerResult(); + + // Construct the response content from the page callback result. + $commands = ajax_prepare_response($page_callback_result); + $json = ajax_render($commands); + + // 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 + $json = '<textarea>' . $json . '</textarea>'; + + // Build the actual response object. + $response = $this->createIframeUploadResponse($event); + $response->setContent($json); + + return $response; + } + /** * Processes a successful controller into an HTTP 200 response. * diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php index ded4ad0da0cdcb3ba71ff8725cf1a4057ac09138..3a6e541ed98930cc7bfa20727861a6fd55340f51 100644 --- a/core/modules/simpletest/drupal_web_test_case.php +++ b/core/modules/simpletest/drupal_web_test_case.php @@ -1834,6 +1834,7 @@ protected function drupalGet($path, array $options = array(), array $headers = a * Retrieve a Drupal path or an absolute path and JSON decode the result. */ protected function drupalGetAJAX($path, array $options = array(), array $headers = array()) { + $headers[] = 'X-Requested-With: XMLHttpRequest'; return drupal_json_decode($this->drupalGet($path, $options, $headers)); } @@ -2041,6 +2042,7 @@ protected function drupalPostAJAX($path, $edit, $triggering_element, $ajax_path } $content = $this->content; $drupal_settings = $this->drupalSettings; + $headers[] = 'X-Requested-With: XMLHttpRequest'; // Get the Ajax settings bound to the triggering element. if (!isset($ajax_settings)) {