blob: 5ebf3f4176650a8a346e15c0073ed73523cc95f8 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
<?php
namespace Drupal\Core\EventSubscriber;
use Drupal\Component\Utility\Html;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
use Drupal\Core\Config\ConfigCrudEvent;
use Drupal\Core\Config\ConfigEvents;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Render\HtmlResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
/**
* High-performance 404 exception subscriber.
*
* This subscriber will return a minimalist 404 response for HTML requests
* without running a full page theming operation.
*
* Fast 404s are configured using the system.performance configuration object.
* There are the following options:
* - system.performance:fast_404.exclude_paths: A regular expression to match
* paths to exclude, such as images generated by image styles, or
* dynamically-resized images. The default pattern provided below also
* excludes the private file system. If you need to add more paths, you can
* add '|path' to the expression.
* - system.performance:fast_404.paths: A regular expression to match paths that
* should return a simple 404 page, rather than the fully themed 404 page. If
* you don't have any aliases ending in htm or html you can add '|s?html?' to
* the expression.
* - system.performance:fast_404.html: The html to return for simple 404 pages.
*/
class Fast404ExceptionHtmlSubscriber extends HttpExceptionSubscriberBase {
/**
* The config factory.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The cache tags invalidator.
*
* @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface
*/
protected $cacheTagsInvalidator;
/**
* Constructs a new Fast404ExceptionHtmlSubscriber.
*
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Drupal\Core\Cache\CacheTagsInvalidatorInterface $cache_tags_invalidator
* The cache tags invalidator.
*/
public function __construct(ConfigFactoryInterface $config_factory, CacheTagsInvalidatorInterface $cache_tags_invalidator) {
$this->configFactory = $config_factory;
$this->cacheTagsInvalidator = $cache_tags_invalidator;
}
/**
* {@inheritdoc}
*/
protected static function getPriority() {
// A very high priority so that it can take precedent over anything else,
// and thus be fast.
return 200;
}
/**
* {@inheritdoc}
*/
protected function getHandledFormats() {
return ['html'];
}
/**
* Handles a 404 error for HTML.
*
* @param \Symfony\Component\HttpKernel\Event\ExceptionEvent $event
* The event to process.
*/
public function on404(ExceptionEvent $event) {
$request = $event->getRequest();
$config = $this->configFactory->get('system.performance');
$exclude_paths = $config->get('fast_404.exclude_paths');
if ($config->get('fast_404.enabled') && $exclude_paths && !preg_match($exclude_paths, $request->getPathInfo())) {
$fast_paths = $config->get('fast_404.paths');
if ($fast_paths && preg_match($fast_paths, $request->getPathInfo())) {
$fast_404_html = strtr($config->get('fast_404.html'), ['@path' => Html::escape($request->getUri())]);
$response = new HtmlResponse($fast_404_html, Response::HTTP_NOT_FOUND);
// Some routes such as system.files conditionally throw a
// NotFoundHttpException depending on URL parameters instead of just the
// route and route parameters, so add the URL cache context to account
// for this.
$cacheable_metadata = new CacheableMetadata();
$cacheable_metadata->setCacheContexts(['url']);
$cacheable_metadata->addCacheTags(['4xx-response']);
$response->addCacheableDependency($cacheable_metadata);
$event->setResponse($response);
}
}
}
/**
* Invalidates 4xx-response cache tag if fast 404 config is changed.
*
* @param \Drupal\Core\Config\ConfigCrudEvent $event
* The configuration event.
*/
public function onConfigSave(ConfigCrudEvent $event): void {
$saved_config = $event->getConfig();
if ($saved_config->getName() === 'system.performance' && $event->isChanged('fast_404')) {
$this->cacheTagsInvalidator->invalidateTags(['4xx-response']);
}
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents(): array {
$events = parent::getSubscribedEvents();
$events[ConfigEvents::SAVE] = 'onConfigSave';
return $events;
}
}
|