Skip to content

Commit f3fa22b

Browse files
committed
minor #11024 [HTTP-cache] Added SSI (Ioni14)
This PR was submitted for the master branch but it was merged into the 4.3 branch instead (closes #11024). Discussion ---------- [HTTP-cache] Added SSI Hello! This is my first "big" contribution to Symfony docs. :) It has many similarities with the ESI one but I think it can be better known and used with a specific doc. I think it's Symfony 2.6 (!) when the SSI feature has been merged, I hope I'm right. I guess there are many typos, I'll fix them as quickly as possible. Thanks for reviewing. ;) Commits ------- d9cdb9d add http cache SSI
2 parents 34da949 + d9cdb9d commit f3fa22b

File tree

1 file changed

+142
-0
lines changed

1 file changed

+142
-0
lines changed

http_cache/ssi.rst

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

0 commit comments

Comments
 (0)