Version 1
[yaffs-website] / web / modules / contrib / redirect / src / EventSubscriber / RouteNormalizerRequestSubscriber.php
diff --git a/web/modules/contrib/redirect/src/EventSubscriber/RouteNormalizerRequestSubscriber.php b/web/modules/contrib/redirect/src/EventSubscriber/RouteNormalizerRequestSubscriber.php
new file mode 100644 (file)
index 0000000..d20f894
--- /dev/null
@@ -0,0 +1,149 @@
+<?php
+
+namespace Drupal\redirect\EventSubscriber;
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Path\PathMatcherInterface;
+use Drupal\Core\Routing\RequestHelper;
+use Drupal\Core\Routing\UrlGeneratorInterface;
+use Drupal\redirect\RedirectChecker;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+
+/**
+ * Normalizes GET requests performing a redirect if required.
+ *
+ * The normalization can be disabled by setting the "_disable_route_normalizer"
+ * request parameter to TRUE. However, this should be done before
+ * onKernelRequestRedirect() method is executed.
+ */
+class RouteNormalizerRequestSubscriber implements EventSubscriberInterface {
+
+  /**
+   * Module specific configuration.
+   *
+   * @var \Drupal\Core\Config\Config
+   */
+  protected $config;
+
+  /**
+   * The URL generator service.
+   *
+   * @var \Drupal\Core\Routing\UrlGeneratorInterface
+   */
+  protected $urlGenerator;
+
+  /**
+   * The path matcher service.
+   *
+   * @var \Drupal\Core\Path\PathMatcherInterface
+   */
+  protected $pathMatcher;
+
+  /**
+   * The redirect checker service.
+   *
+   * @var \Drupal\redirect\RedirectChecker
+   */
+  protected $redirectChecker;
+
+  /**
+   * Constructs a RouteNormalizerRequestSubscriber object.
+   *
+   * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
+   *   The URL generator service.
+   * @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
+   *   The path matcher service.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config
+   *   The config.
+   * @param \Drupal\redirect\RedirectChecker $redirect_checker
+   *   The redirect checker service.
+   *   The value of the route_normalizer_enabled container parameter.
+   */
+  public function __construct(UrlGeneratorInterface $url_generator, PathMatcherInterface $path_matcher, ConfigFactoryInterface $config, RedirectChecker $redirect_checker) {
+    $this->urlGenerator = $url_generator;
+    $this->pathMatcher = $path_matcher;
+    $this->redirectChecker = $redirect_checker;
+    $this->config = $config->get('redirect.settings');
+  }
+
+  /**
+   * Performs a redirect if the URL changes in routing.
+   *
+   * The redirect happens if a URL constructed from the current route is
+   * different from the requested one. Examples:
+   * - Language negotiation system detected a language to use, and that language
+   *   has a path prefix: perform a redirect to the language prefixed URL.
+   * - A route that's set as the front page is requested: redirect to the front
+   *   page.
+   * - Requested path has an alias: redirect to alias.
+   *
+   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+   *   The Event to process.
+   */
+  public function onKernelRequestRedirect(GetResponseEvent $event) {
+
+    if (!$this->config->get('route_normalizer_enabled') || !$event->isMasterRequest()) {
+      return;
+    }
+
+    $request = $event->getRequest();
+    if ($request->attributes->get('_disable_route_normalizer')) {
+      return;
+    }
+
+    if ($this->redirectChecker->canRedirect($request)) {
+      // The "<current>" placeholder can be used for all routes except the front
+      // page because it's not a real route.
+      $route_name = $this->pathMatcher->isFrontPage() ? '<front>' : '<current>';
+
+      // Don't pass in the query here using $request->query->all()
+      // since that can potentially modify the query parameters.
+      $options = ['absolute' => TRUE];
+      $redirect_uri = $this->urlGenerator->generateFromRoute($route_name, [], $options);
+
+      // Strip off query parameters added by the route such as a CSRF token.
+      if (strpos($redirect_uri, '?') !== FALSE) {
+        $redirect_uri  = strtok($redirect_uri, '?');
+      }
+
+      // Append back the request query string from $_SERVER.
+      $query_string = $request->server->get('QUERY_STRING');
+      if ($query_string) {
+        $redirect_uri .= '?' . $query_string;
+      }
+
+      // Remove /index.php from redirect uri the hard way.
+      if (!RequestHelper::isCleanUrl($request)) {
+        // This needs to be fixed differently.
+        $redirect_uri = str_replace('/index.php', '', $redirect_uri);
+      }
+
+      $original_uri = $request->getSchemeAndHttpHost() . $request->getRequestUri();
+      $original_uri = urldecode($original_uri);
+      $redirect_uri = urldecode($redirect_uri);
+      if ($redirect_uri != $original_uri) {
+        $response = new RedirectResponse($redirect_uri, $this->config->get('default_status_code'));
+        $response->headers->set('X-Drupal-Route-Normalizer', 1);
+        $event->setResponse($response);
+        // Disable page cache for redirects as that results in unpredictable
+        // behavior, e.g. when a trailing ? without query parameters is
+        // involved.
+        // @todo Remove when https://www.drupal.org/node/2761639 is fixed in
+        //   Drupal core.
+        \Drupal::service('page_cache_kill_switch')->trigger();
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onKernelRequestRedirect', 30);
+    return $events;
+  }
+
+}