File: base.rst

package info (click to toggle)
python-whitenoise 6.8.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 472 kB
  • sloc: python: 2,040; makefile: 132; javascript: 10
file content (302 lines) | stat: -rw-r--r-- 10,757 bytes parent folder | download
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
Using WhiteNoise with any WSGI application
==========================================

.. note:: These instructions apply to any WSGI application. However, for Django
    applications you would be better off using the :doc:`WhiteNoiseMiddleware
    <django>` class which makes integration easier.

To enable WhiteNoise you need to wrap your existing WSGI application in a
WhiteNoise instance and tell it where to find your static files. For example:

.. code-block:: python

   from whitenoise import WhiteNoise

   from my_project import MyWSGIApp

   application = MyWSGIApp()
   application = WhiteNoise(application, root="/path/to/static/files")
   application.add_files("/path/to/more/static/files", prefix="more-files/")

On initialization, WhiteNoise walks over all the files in the directories that have
been added (descending into sub-directories) and builds a list of available static files.
Any requests which match a static file get served by WhiteNoise, all others are passed
through to the original WSGI application.

See the sections on :ref:`compression <compression>` and :ref:`caching <caching>`
for further details.


WhiteNoise API
--------------

.. class:: WhiteNoise(application, root=None, prefix=None, \**kwargs)

   :param callable application: Original WSGI application
   :param str root: If set, passed to ``add_files`` method
   :param str prefix: If set, passed to ``add_files`` method
   :param  \**kwargs: Sets :ref:`configuration attributes <configuration>` for this instance

.. method:: WhiteNoise.add_files(root, prefix=None)

   :param str root: Absolute path to a directory of static files to be served
   :param str prefix: If set, the URL prefix under which the files will be served. Trailing slashes
    are automatically added.


.. _compression:

Compression Support
-------------------

When WhiteNoise builds its list of available files it checks for corresponding
files with a ``.gz`` and a ``.br`` suffix (e.g., ``scripts/app.js``,
``scripts/app.js.gz`` and ``scripts/app.js.br``). If it finds them, it will
assume that they are (respectively) gzip and `brotli <https://en.wikipedia.org/wiki/Brotli>`_
compressed versions of the original file and it will serve them in preference
to the uncompressed version where clients indicate that they that compression
format (see note on Amazon S3 for why this behaviour is important).

.. _cli-utility:

WhiteNoise comes with a command line utility which will generate compressed
versions of your files for you. Note that in order for brotli compression to
work the `Brotli Python package <https://pypi.org/project/Brotli/>`_ must be installed.


Usage is simple:

.. code-block:: console

   $ python -m whitenoise.compress --help
   usage: compress.py [-h] [-q] [--no-gzip] [--no-brotli]
                      root [extensions [extensions ...]]

   Search for all files inside <root> *not* matching <extensions> and produce
   compressed versions with '.gz' and '.br' suffixes (as long as this results in
   a smaller file)

   positional arguments:
     root         Path root from which to search for files
     extensions   File extensions to exclude from compression (default: jpg,
                  jpeg, png, gif, webp, zip, gz, tgz, bz2, tbz, xz, br, swf, flv,
                  woff, woff2)

   optional arguments:
     -h, --help   show this help message and exit
     -q, --quiet  Don't produce log output
     --no-gzip    Don't produce gzip '.gz' files
     --no-brotli  Don't produce brotli '.br' files

You can either run this during development and commit your compressed files to
your repository, or you can run this as part of your build and deploy processes.
(Note that this is handled automatically in Django if you're using the custom
storage backend.)


.. _caching:

Caching Headers
---------------

By default, WhiteNoise sets a max-age header on all responses it sends. You can
configure this by passing a ``max_age`` keyword argument.

WhiteNoise sets both ``Last-Modified`` and ``ETag`` headers for all files and
will return Not Modified responses where appropriate. The ETag header uses the
same format as nginx which is based on the size and last-modified time of the file.
If you want to use a different scheme for generating ETags you can set them via
you own function by using the :any:`add_headers_function` option.

Most modern static asset build systems create uniquely named versions of each
file. This results in files which are immutable (i.e., they can never change
their contents) and can therefore by cached indefinitely.  In order to take
advantage of this, WhiteNoise needs to know which files are immutable. This can
be done using the :any:`immutable_file_test` option which accepts a reference to
a function.

The exact details of how you implement this method will depend on your
particular asset build system but see the :any:`option documentation
<immutable_file_test>` for a simple example.

Once you have implemented this, any files which are flagged as immutable will
have "cache forever" headers set.


.. _index_files:

Index Files
-----------

When the :any:`index_file` option is enabled:

* Visiting ``/example/`` will serve the file at ``/example/index.html``
* Visiting ``/example`` will redirect (302) to ``/example/``
* Visiting ``/example/index.html`` will redirect (302) to ``/example/``

If you want to something other than ``index.html`` as the index file, then you
can also set this option to an alternative filename.


Using a Content Distribution Network
------------------------------------

See the instructions for :ref:`using a CDN with Django <cdn>` . The same principles
apply here although obviously the exact method for generating the URLs for your static
files will depend on the libraries you're using.


Redirecting to HTTPS
--------------------

WhiteNoise does not handle redirection itself, but works well alongside
`wsgi-sslify`_, which performs HTTP to HTTPS redirection as well as optionally
setting an HSTS header. Simply wrap the WhiteNoise WSGI application with
``sslify()`` - see the `wsgi-sslify`_ documentation for more details.

.. _wsgi-sslify: https://github.com/jacobian/wsgi-sslify


.. _configuration:

Configuration attributes
------------------------

These can be set by passing keyword arguments to the constructor, or by
sub-classing WhiteNoise and setting the attributes directly.

.. attribute:: autorefresh

    :default: ``False``

    Recheck the filesystem to see if any files have changed before responding.
    This is designed to be used in development where it can be convenient to
    pick up changes to static files without restarting the server. For both
    performance and security reasons, this setting should not be used in
    production.

.. attribute:: max_age

    :default: ``60``

    Time (in seconds) for which browsers and proxies should cache files.

    The default is chosen to be short enough not to cause problems with stale versions but
    long enough that, if you're running WhiteNoise behind a CDN, the CDN will still take
    the majority of the strain during times of heavy load.

    Set to ``None`` to disable setting any ``Cache-Control`` header on non-versioned files.

.. attribute:: index_file

    :default: ``False``

    If ``True`` enable :ref:`index file serving <index_files>`. If set to a non-empty
    string, enable index files and use that string as the index file name.

.. attribute:: mimetypes

    :default: ``None``

    A dictionary mapping file extensions (lowercase) to the mimetype for that
    extension. For example: ::

        {'.foo': 'application/x-foo'}

    Note that WhiteNoise ships with its own default set of mimetypes and does
    not use the system-supplied ones (e.g. ``/etc/mime.types``). This ensures
    that it behaves consistently regardless of the environment in which it's
    run.  View the defaults in the :ghfile:`media_types.py
    <whitenoise/media_types.py>` file.

    In addition to file extensions, mimetypes can be specified by supplying the entire
    filename, for example: ::

        {'some-special-file': 'application/x-custom-type'}

.. attribute:: charset

    :default: ``utf-8``

    Charset to add as part of the ``Content-Type`` header for all files whose
    mimetype allows a charset.

.. attribute:: allow_all_origins

    :default: ``True``

    Toggles whether to send an ``Access-Control-Allow-Origin: *`` header for all
    static files.

    This allows cross-origin requests for static files which means your static files
    will continue to work as expected even if they are served via a CDN and therefore
    on a different domain. Without this your static files will *mostly* work, but you
    may have problems with fonts loading in Firefox, or accessing images in canvas
    elements, or other mysterious things.

    The W3C `explicitly state`__ that this behaviour is safe for publicly
    accessible files.

.. __: https://www.w3.org/TR/cors/#security

.. attribute:: add_headers_function

    :default: ``None``

    Reference to a function which is passed the headers object for each static file,
    allowing it to modify them.

    For example: ::

        def force_download_pdfs(headers, path, url):
            if path.endswith('.pdf'):
                headers['Content-Disposition'] = 'attachment'

        application = WhiteNoise(application,
                                 add_headers_function=force_download_pdfs)

    The function is passed:

    headers
      A `wsgiref.headers`__ instance (which you can treat just as a dict) containing
      the headers for the current file

    path
      The absolute path to the local file

    url
      The host-relative URL of the file e.g. ``/static/styles/app.css``

    The function should not return anything; changes should be made by modifying the
    headers dictionary directly.

.. __: https://docs.python.org/3/library/wsgiref.html#module-wsgiref.headers


.. attribute:: immutable_file_test

    :default: ``return False``

    Reference to function, or string.

    If a reference to a function, this is passed the path and URL for each
    static file and should return whether that file is immutable, i.e.
    guaranteed not to change, and so can be safely cached forever.

    If a string, this is treated as a regular expression and each file's URL is
    matched against it.

    Example: ::

        def immutable_file_test(path, url):
            # Match filename with 12 hex digits before the extension
            # e.g. app.db8f2edc0c8a.js
            return re.match(r'^.+\.[0-9a-f]{12}\..+$', url)

    The function is passed:

    path
      The absolute path to the local file

    url
      The host-relative URL of the file e.g. ``/static/styles/app.css``