Skip to content

Commit c5cef1d

Browse files
committed
Merge branch '4.4'
* 4.4: Tweaks #11024 add http cache SSI
2 parents 611ea5a + 4ae7a7d commit c5cef1d

File tree

1 file changed

+141
-0
lines changed

1 file changed

+141
-0
lines changed

http_cache/ssi.rst

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
.. index::
2+
single: Cache; SSI
3+
single: SSI
4+
5+
.. _server-side-includes:
6+
7+
Working with Server Side Includes
8+
=================================
9+
10+
In a similar way as :doc:`ESI (Edge Side Includes) </http_cache/esi>`,
11+
SSI can be used to control HTTP caching on fragments of a response.
12+
The most important difference that is SSI is known directly by most
13+
web servers like `Apache`_, `Nginx`_ etc.
14+
15+
The SSI instructions are done via HTML comments:
16+
17+
.. code-block:: html
18+
19+
<!DOCTYPE html>
20+
<html>
21+
<body>
22+
<!-- ... some content -->
23+
24+
<!-- Embed the content of another page here -->
25+
<!--#include virtual="http://..." -->
26+
27+
<!-- ... more content -->
28+
</body>
29+
</html>
30+
31+
There are some other `available directives`_ but
32+
Symfony manages only the ``#include virtual`` one.
33+
34+
.. caution::
35+
36+
Be careful with SSI, your website may be victim of injections.
37+
Please read this `OWASP article`_ first!
38+
39+
When the web server reads an SSI directive, it requests the given URI or gives
40+
directly from its cache. It repeats this process until there is no more
41+
SSI directives to handle. Then, it merges all responses into one and sends
42+
it to the client.
43+
44+
.. _using-ssi-in-symfony:
45+
46+
Using SSI in Symfony
47+
~~~~~~~~~~~~~~~~~~~~
48+
49+
First, to use SSI, be sure to enable it in your application configuration:
50+
51+
.. configuration-block::
52+
53+
.. code-block:: yaml
54+
55+
# config/packages/framework.yaml
56+
framework:
57+
ssi: { enabled: true }
58+
59+
.. code-block:: xml
60+
61+
<!-- config/packages/framework.xml -->
62+
<?xml version="1.0" encoding="UTF-8" ?>
63+
<container xmlns="http://symfony.com/schema/dic/symfony"
64+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
65+
xmlns:framework="http://symfony.com/schema/dic/symfony"
66+
xsi:schemaLocation="http://symfony.com/schema/dic/services
67+
http://symfony.com/schema/dic/services/services-1.0.xsd
68+
http://symfony.com/schema/dic/symfony
69+
http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
70+
71+
<framework:config>
72+
<framework:ssi enabled="true"/>
73+
</framework:config>
74+
</container>
75+
76+
.. code-block:: php
77+
78+
// config/packages/framework.php
79+
$container->loadFromExtension('framework', [
80+
'ssi' => ['enabled' => true],
81+
]);
82+
83+
Suppose you have a page with private content like a Profile page and you want
84+
to cache a static GDPR content block. With SSI, you can add some expiration
85+
on this block and keep the page private::
86+
87+
// src/Controller/ProfileController.php
88+
89+
// ...
90+
class ProfileController extends AbstractController
91+
{
92+
public function index(): Response
93+
{
94+
// by default, responses are private
95+
return $this->render('profile/index.html.twig');
96+
}
97+
98+
public function gdpr(): Response
99+
{
100+
$response = $this->render('profile/gdpr.html.twig');
101+
102+
// sets to public and adds some expiration
103+
$response->setSharedMaxAge(600);
104+
105+
return $response;
106+
}
107+
}
108+
109+
The profile index page has not public caching, but the GDPR block has
110+
10 minutes of expiration. Let's include this block into the main one:
111+
112+
.. code-block:: twig
113+
114+
{# templates/profile/index.html.twig #}
115+
116+
{# you can use a controller reference #}
117+
{{ render_ssi(controller('App\Controller\ProfileController::gdpr')) }}
118+
119+
{# ... or a URL #}
120+
{{ render_ssi(url('profile_gdpr')) }}
121+
122+
The ``render_ssi`` twig helper will generate something like:
123+
124+
.. code-block:: html
125+
126+
<!--#include virtual="/_fragment?_hash=abcdef1234&_path=_controller=App\Controller\ProfileController::gdpr" -->
127+
128+
``render_ssi`` ensures that SSI directive are generated only if the request
129+
has the header requirement like ``Surrogate-Capability: device="SSI/1.0"``
130+
(normally given by the web server).
131+
Otherwise it will embed directly the sub-response.
132+
133+
.. note::
134+
135+
For more information about Symfony cache fragments, take a tour on
136+
the :ref:`ESI documentation <http_cache-fragments>`.
137+
138+
.. _`Apache`: https://httpd.apache.org/docs/current/en/howto/ssi.html
139+
.. _`Nginx`: https://nginx.org/en/docs/http/ngx_http_ssi_module.html
140+
.. _`available directives`: https://en.wikipedia.org/wiki/Server_Side_Includes#Directives
141+
.. _`OWASP article`: https://www.owasp.org/index.php/Server-Side_Includes_(SSI)_Injection

0 commit comments

Comments
 (0)