Skip to content

Commit a29f88c

Browse files
committed
document that headers must be set before streaming
1 parent f00ad42 commit a29f88c

4 files changed

Lines changed: 55 additions & 8 deletions

File tree

docs/patterns/streaming.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@ roundtrip to the filesystem?
88

99
The answer is by using generators and direct responses.
1010

11+
HTTP Response Behavior
12+
----------------------
13+
14+
**Headers cannot be changed after the streaming response starts.**
15+
16+
When using streaming, it's important to be aware of the order than an HTTP
17+
response is sent. All headers must be sent first, then the body. More headers
18+
cannot be sent after the body has begun. Therefore, you must make sure all
19+
headers are set before starting the response, outside the generator.
20+
21+
In particular, if the generator will access ``session``, be sure to do so in the
22+
view as well so that the ``Vary: cookie`` header will be set. Do not modify the
23+
session in the generator, as the ``Set-Cookie`` header will already be sent.
24+
25+
1126
Basic Usage
1227
-----------
1328

docs/templating.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,5 +225,11 @@ functions to make this easier to use.
225225
return stream_template("timeline.html")
226226
227227
These functions automatically apply the
228-
:func:`~flask.stream_with_context` wrapper if a request is active, so
229-
that it remains available in the template.
228+
:func:`~flask.stream_with_context` wrapper if a request is active, so that
229+
:data:`.request`, :data:`.session`, and :data:`.g` remain available in the
230+
template.
231+
232+
More headers cannot be sent after the body has begun. Therefore, you must
233+
make sure all headers are set before starting the response. In particular,
234+
if the template will access ``session``, be sure to do so in the view as
235+
well so that the ``Vary: cookie`` header will be set.

src/flask/ctx.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,27 @@ def add_header(response):
153153

154154

155155
def copy_current_request_context(f: F) -> F:
156-
"""A helper function that decorates a function to retain the current
157-
request context. This is useful when working with greenlets. The moment
158-
the function is decorated a copy of the request context is created and
159-
then pushed when the function is called. The current session is also
160-
included in the copied request context.
156+
"""Decorate a function to run inside the current request context. This can
157+
be used when starting a background task, otherwise it will not see the app
158+
and request objects that were active in the parent.
161159
162-
Example::
160+
.. warning::
161+
162+
Due to the following caveats, it is often safer (and simpler) to pass
163+
the data you need when starting the task, rather than using this and
164+
relying on the context objects.
165+
166+
In order to avoid execution switching partially though reading data, either
167+
read the request body (access ``form``, ``json``, ``data``, etc) before
168+
starting the task, or use a lock. This can be an issue when using threading,
169+
but shouldn't be an issue when using greenlet/gevent or asyncio.
170+
171+
If the task will access ``session``, be sure to do so in the parent as well
172+
so that the ``Vary: cookie`` header will be set. Modifying ``session`` in
173+
the task should be avoided, as it may execute after the response cookie has
174+
already been written.
175+
176+
.. code-block:: python
163177
164178
import gevent
165179
from flask import copy_current_request_context

src/flask/helpers.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,18 @@ def stream_with_context(
6868
available, even though at the point the generator runs the request context
6969
will typically have ended.
7070
71+
.. warning::
72+
73+
Due to the following caveat, it is often safer to pass the data you
74+
need as arguments to the generator, rather than relying on the context
75+
objects.
76+
77+
More headers cannot be sent after the body has begun. Therefore, you must
78+
make sure all headers are set before starting the response. In particular,
79+
if the generator will access ``session``, be sure to do so in the view as
80+
well so that the ``Vary: cookie`` header will be set. Do not modify the
81+
session in the generator, as the ``Set-Cookie`` header will already be sent.
82+
7183
Use it as a decorator on a generator function:
7284
7385
.. code-block:: python

0 commit comments

Comments
 (0)