public function testAccess(Request $request, EditorInterface $editor, EmbedButtonInterface $embed_button)
 {
     $text = $request->get('value');
     $response = new HtmlResponse(['#markup' => $text, '#cache' => ['contexts' => ['url.query_args:value']]]);
     if ($text == '') {
         $response->setStatusCode(404);
     }
     return $response;
 }
 /**
  * Sets headers on a response object.
  *
  * @param \Drupal\Core\Render\HtmlResponse $response
  *   The HTML response to update.
  * @param array $headers
  *   The headers to set, as an array. The items in this array should be as
  *   follows:
  *   - The header name.
  *   - The header value.
  *   - (optional) Whether to replace a current value with the new one, or add
  *     it to the others. If the value is not replaced, it will be appended,
  *     resulting in a header like this: 'Header: value1,value2'
  */
 protected function setHeaders(HtmlResponse $response, array $headers)
 {
     foreach ($headers as $values) {
         $name = $values[0];
         $value = $values[1];
         $replace = !empty($values[2]);
         // Drupal treats the HTTP response status code like a header, even though
         // it really is not.
         if (strtolower($name) === 'status') {
             $response->setStatusCode($value);
         } else {
             $response->headers->set($name, $value, $replace);
         }
     }
 }
 /**
  * Sends no-JS BigPipe placeholders' replacements as embedded HTML responses.
  *
  * @param string $html
  *   HTML markup.
  * @param array $no_js_placeholders
  *   Associative array; the no-JS BigPipe placeholders. Keys are the BigPipe
  *   selectors.
  * @param \Drupal\Core\Asset\AttachedAssetsInterface $cumulative_assets
  *   The cumulative assets sent so far; to be updated while rendering no-JS
  *   BigPipe placeholders.
  *
  * @throws \Exception
  *   If an exception is thrown during the rendering of a placeholder, it is
  *   caught to allow the other placeholders to still be replaced. But when
  *   error logging is configured to be verbose, the exception is rethrown to
  *   simplify debugging.
  */
 protected function sendNoJsPlaceholders($html, $no_js_placeholders, AttachedAssetsInterface $cumulative_assets)
 {
     // Split the HTML on every no-JS placeholder string.
     $prepare_for_preg_split = function ($placeholder_string) {
         return '(' . preg_quote($placeholder_string, '/') . ')';
     };
     $preg_placeholder_strings = array_map($prepare_for_preg_split, array_keys($no_js_placeholders));
     $fragments = preg_split('/' . implode('|', $preg_placeholder_strings) . '/', $html, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
     foreach ($fragments as $fragment) {
         // If the fragment isn't one of the no-JS placeholders, it is the HTML in
         // between placeholders and it must be printed & flushed immediately. The
         // rest of the logic in the loop handles the placeholders.
         if (!isset($no_js_placeholders[$fragment])) {
             print $fragment;
             flush();
             continue;
         }
         $placeholder = $fragment;
         assert('isset($no_js_placeholders[$placeholder])');
         $token = Crypt::randomBytesBase64(55);
         // Render the placeholder, but include the cumulative settings assets, so
         // we can calculate the overall settings for the entire page.
         $placeholder_plus_cumulative_settings = ['placeholder' => $no_js_placeholders[$placeholder], 'cumulative_settings_' . $token => ['#attached' => ['drupalSettings' => $cumulative_assets->getSettings()]]];
         try {
             $elements = $this->renderPlaceholder($placeholder, $placeholder_plus_cumulative_settings);
         } catch (\Exception $e) {
             if (\Drupal::config('system.logging')->get('error_level') === ERROR_REPORTING_DISPLAY_VERBOSE) {
                 throw $e;
             } else {
                 trigger_error($e, E_USER_ERROR);
                 continue;
             }
         }
         // Create a new HtmlResponse. Ensure the CSS and (non-bottom) JS is sent
         // before the HTML they're associated with. In other words: ensure the
         // critical assets for this placeholder's markup are loaded first.
         // @see \Drupal\Core\Render\HtmlResponseSubscriber
         // @see template_preprocess_html()
         $css_placeholder = '<nojs-bigpipe-placeholder-styles-placeholder token="' . $token . '">';
         $js_placeholder = '<nojs-bigpipe-placeholder-scripts-placeholder token="' . $token . '">';
         $elements['#markup'] = BigPipeMarkup::create($css_placeholder . $js_placeholder . (string) $elements['#markup']);
         $elements['#attached']['html_response_attachment_placeholders']['styles'] = $css_placeholder;
         $elements['#attached']['html_response_attachment_placeholders']['scripts'] = $js_placeholder;
         $html_response = new HtmlResponse();
         $html_response->setContent($elements);
         $html_response->getCacheableMetadata()->setCacheMaxAge(0);
         // Push a fake request with the asset libraries loaded so far and dispatch
         // KernelEvents::RESPONSE event. This results in the attachments for the
         // HTML response being processed by HtmlResponseAttachmentsProcessor and
         // hence:
         // - the HTML to load the CSS can be rendered.
         // - the HTML to load the JS (at the top) can be rendered.
         $fake_request = $this->requestStack->getMasterRequest()->duplicate();
         $fake_request->request->set('ajax_page_state', ['libraries' => implode(',', $cumulative_assets->getAlreadyLoadedLibraries())]);
         try {
             $html_response = $this->filterEmbeddedResponse($fake_request, $html_response);
         } catch (\Exception $e) {
             if (\Drupal::config('system.logging')->get('error_level') === ERROR_REPORTING_DISPLAY_VERBOSE) {
                 throw $e;
             } else {
                 trigger_error($e, E_USER_ERROR);
                 continue;
             }
         }
         // Send this embedded HTML response.
         print $html_response->getContent();
         flush();
         // Another placeholder was rendered and sent, track the set of asset
         // libraries sent so far. Any new settings also need to be tracked, so
         // they can be sent in ::sendPreBody().
         $cumulative_assets->setAlreadyLoadedLibraries(array_merge($cumulative_assets->getAlreadyLoadedLibraries(), $html_response->getAttachments()['library']));
         $cumulative_assets->setSettings($html_response->getAttachments()['drupalSettings']);
     }
 }
Example #4
0
 /**
  * Sends no-JS BigPipe placeholders' replacements as embedded HTML responses.
  *
  * @param string $html
  *   HTML markup.
  * @param array $no_js_placeholders
  *   Associative array; the no-JS BigPipe placeholders. Keys are the BigPipe
  *   selectors.
  * @param \Drupal\Core\Asset\AttachedAssetsInterface $cumulative_assets
  *   The cumulative assets sent so far; to be updated while rendering no-JS
  *   BigPipe placeholders.
  */
 protected function sendNoJsPlaceholders($html, $no_js_placeholders, AttachedAssetsInterface $cumulative_assets)
 {
     $fragments = explode('<div data-big-pipe-selector-nojs="', $html);
     print array_shift($fragments);
     ob_end_flush();
     flush();
     foreach ($fragments as $fragment) {
         $t = explode('"></div>', $fragment, 2);
         $placeholder = $t[0];
         if (!isset($no_js_placeholders[$placeholder])) {
             continue;
         }
         $token = Crypt::randomBytesBase64(55);
         // Render the placeholder, but include the cumulative settings assets, so
         // we can calculate the overall settings for the entire page.
         $placeholder_plus_cumulative_settings = ['placeholder' => $no_js_placeholders[$placeholder], 'cumulative_settings_' . $token => ['#attached' => ['drupalSettings' => $cumulative_assets->getSettings()]]];
         $elements = $this->renderPlaceholder($placeholder, $placeholder_plus_cumulative_settings);
         // Create a new HtmlResponse. Ensure the CSS and (non-bottom) JS is sent
         // before the HTML they're associated with. In other words: ensure the
         // critical assets for this placeholder's markup are loaded first.
         // @see \Drupal\Core\Render\HtmlResponseSubscriber
         // @see template_preprocess_html()
         $css_placeholder = '<nojs-bigpipe-placeholder-styles-placeholder token="' . $token . '">';
         $js_placeholder = '<nojs-bigpipe-placeholder-scripts-placeholder token="' . $token . '">';
         $elements['#markup'] = Markup::create($css_placeholder . $js_placeholder . (string) $elements['#markup']);
         $elements['#attached']['html_response_attachment_placeholders']['styles'] = $css_placeholder;
         $elements['#attached']['html_response_attachment_placeholders']['scripts'] = $js_placeholder;
         $html_response = new HtmlResponse();
         $html_response->setContent($elements);
         $html_response->getCacheableMetadata()->setCacheMaxAge(0);
         // Push a fake request with the asset libraries loaded so far and dispatch
         // KernelEvents::RESPONSE event. This results in the attachments for the
         // HTML response being processed by HtmlResponseAttachmentsProcessor and
         // hence:
         // - the HTML to load the CSS can be rendered.
         // - the HTML to load the JS (at the top) can be rendered.
         $fake_request = $this->requestStack->getMasterRequest()->duplicate();
         $fake_request->request->set('ajax_page_state', ['libraries' => implode(',', $cumulative_assets->getAlreadyLoadedLibraries())] + $cumulative_assets->getSettings()['ajaxPageState']);
         $this->requestStack->push($fake_request);
         $event = new FilterResponseEvent($this->httpKernel, $fake_request, HttpKernelInterface::SUB_REQUEST, $html_response);
         $this->eventDispatcher->dispatch(KernelEvents::RESPONSE, $event);
         $html_response = $event->getResponse();
         $this->requestStack->pop();
         // Send this embedded HTML response.
         print $html_response->getContent();
         print $t[1];
         flush();
         // Another placeholder was rendered and sent, track the set of asset
         // libraries sent so far. Any new settings also need to be tracked, so
         // they can be sent in ::sendPreBody().
         // @todo What if drupalSettings already was printed in the HTML <head>? That case is not yet handled. In that case, no-JS BigPipe would cause broken (incomplete) drupalSettingsā€¦ This would not matter if it were only used if JS is not enabled, but that's not the only use case. However, this
         $final_settings = $html_response->getAttachments()['drupalSettings'];
         $cumulative_assets->setAlreadyLoadedLibraries(explode(',', $final_settings['ajaxPageState']['libraries']));
         $cumulative_assets->setSettings($final_settings);
     }
 }
 /**
  * Sets headers on a response object.
  *
  * @param \Drupal\Core\Render\HtmlResponse $response
  *   The HTML response to update.
  * @param array $headers
  *   The headers to set.
  */
 protected function setHeaders(HtmlResponse $response, array $headers)
 {
     foreach ($headers as $name => $value) {
         // Drupal treats the HTTP response status code like a header, even though
         // it really is not.
         if ($name === 'status') {
             $response->setStatusCode($value);
         }
         $response->headers->set($name, $value, FALSE);
     }
 }
Example #6
0
 /**
  * Sends no-JS BigPipe placeholders' replacements as embedded HTML responses.
  *
  * @param string $html
  *   HTML markup.
  * @param array $no_js_placeholders
  *   Associative array; the no-JS BigPipe placeholders. Keys are the BigPipe
  *   selectors.
  * @param \Drupal\Core\Asset\AttachedAssetsInterface $cumulative_assets
  *   The cumulative assets sent so far; to be updated while rendering no-JS
  *   BigPipe placeholders.
  */
 protected function sendNoJsPlaceholders($html, $no_js_placeholders, AttachedAssetsInterface $cumulative_assets)
 {
     // Split the HTML on every no-JS placeholder string.
     $prepare_for_preg_split = function ($placeholder_string) {
         return '(' . preg_quote($placeholder_string, '/') . ')';
     };
     $preg_placeholder_strings = array_map($prepare_for_preg_split, array_keys($no_js_placeholders));
     $fragments = preg_split('/' . implode('|', $preg_placeholder_strings) . '/', $html, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
     foreach ($fragments as $fragment) {
         // If the fragment isn't one of the no-JS placeholders, it is the HTML in
         // between placeholders and it must be printed & flushed immediately. The
         // rest of the logic in the loop handles the placeholders.
         if (!isset($no_js_placeholders[$fragment])) {
             print $fragment;
             flush();
             continue;
         }
         $placeholder = $fragment;
         assert('isset($no_js_placeholders[$placeholder])');
         $token = Crypt::randomBytesBase64(55);
         // Render the placeholder, but include the cumulative settings assets, so
         // we can calculate the overall settings for the entire page.
         $placeholder_plus_cumulative_settings = ['placeholder' => $no_js_placeholders[$placeholder], 'cumulative_settings_' . $token => ['#attached' => ['drupalSettings' => $cumulative_assets->getSettings()]]];
         $elements = $this->renderPlaceholder($placeholder, $placeholder_plus_cumulative_settings);
         // Create a new HtmlResponse. Ensure the CSS and (non-bottom) JS is sent
         // before the HTML they're associated with. In other words: ensure the
         // critical assets for this placeholder's markup are loaded first.
         // @see \Drupal\Core\Render\HtmlResponseSubscriber
         // @see template_preprocess_html()
         $css_placeholder = '<nojs-bigpipe-placeholder-styles-placeholder token="' . $token . '">';
         $js_placeholder = '<nojs-bigpipe-placeholder-scripts-placeholder token="' . $token . '">';
         $elements['#markup'] = Markup::create($css_placeholder . $js_placeholder . (string) $elements['#markup']);
         $elements['#attached']['html_response_attachment_placeholders']['styles'] = $css_placeholder;
         $elements['#attached']['html_response_attachment_placeholders']['scripts'] = $js_placeholder;
         $html_response = new HtmlResponse();
         $html_response->setContent($elements);
         $html_response->getCacheableMetadata()->setCacheMaxAge(0);
         // Push a fake request with the asset libraries loaded so far and dispatch
         // KernelEvents::RESPONSE event. This results in the attachments for the
         // HTML response being processed by HtmlResponseAttachmentsProcessor and
         // hence:
         // - the HTML to load the CSS can be rendered.
         // - the HTML to load the JS (at the top) can be rendered.
         $fake_request = $this->requestStack->getMasterRequest()->duplicate();
         $fake_request->request->set('ajax_page_state', ['libraries' => implode(',', $cumulative_assets->getAlreadyLoadedLibraries())]);
         $this->requestStack->push($fake_request);
         $event = new FilterResponseEvent($this->httpKernel, $fake_request, HttpKernelInterface::SUB_REQUEST, $html_response);
         $this->eventDispatcher->dispatch(KernelEvents::RESPONSE, $event);
         $html_response = $event->getResponse();
         $this->requestStack->pop();
         // Send this embedded HTML response.
         print $html_response->getContent();
         flush();
         // Another placeholder was rendered and sent, track the set of asset
         // libraries sent so far. Any new settings also need to be tracked, so
         // they can be sent in ::sendPreBody().
         // @todo What if drupalSettings already was printed in the HTML <head>? That case is not yet handled. In that case, no-JS BigPipe would cause broken (incomplete) drupalSettingsā€¦ This would not matter if it were only used if JS is not enabled, but that's not the only use case. However, this
         $cumulative_assets->setAlreadyLoadedLibraries(array_merge($cumulative_assets->getAlreadyLoadedLibraries(), $html_response->getAttachments()['library']));
         $cumulative_assets->setSettings($html_response->getAttachments()['drupalSettings']);
     }
 }