diff --git a/CHANGES b/CHANGES index a3504ad5..53d11697 100644 --- a/CHANGES +++ b/CHANGES @@ -67,6 +67,9 @@ Major release, unreleased of the generic bad request message. (`#2348`_) - Allow registering new tags with ``TaggedJSONSerializer`` to support storing other types in the session cookie. (`#2352`_) +- Only open the session if the request has not been pushed onto the context + stack yet. This allows ``stream_with_context`` generators to access the same + session that the containing view uses. (`#2354`_) .. _#1489: https://github.com/pallets/flask/pull/1489 .. _#1621: https://github.com/pallets/flask/pull/1621 @@ -87,6 +90,7 @@ Major release, unreleased .. _#2326: https://github.com/pallets/flask/pull/2326 .. _#2348: https://github.com/pallets/flask/pull/2348 .. _#2352: https://github.com/pallets/flask/pull/2352 +.. _#2354: https://github.com/pallets/flask/pull/2354 Version 0.12.2 -------------- diff --git a/flask/ctx.py b/flask/ctx.py index 70743de6..9e184c18 100644 --- a/flask/ctx.py +++ b/flask/ctx.py @@ -325,15 +325,18 @@ class RequestContext(object): _request_ctx_stack.push(self) - # Open the session at the moment that the request context is - # available. This allows a custom open_session method to use the - # request context (e.g. code that access database information - # stored on `g` instead of the appcontext). - session_interface = self.app.session_interface - self.session = session_interface.open_session(self.app, self.request) - + # Open the session at the moment that the request context is available. + # This allows a custom open_session method to use the request context. + # Only open a new session if this is the first time the request was + # pushed, otherwise stream_with_context loses the session. if self.session is None: - self.session = session_interface.make_null_session(self.app) + session_interface = self.app.session_interface + self.session = session_interface.open_session( + self.app, self.request + ) + + if self.session is None: + self.session = session_interface.make_null_session(self.app) def pop(self, exc=_sentinel): """Pops the request context and unbinds it by doing that. This will diff --git a/tests/test_helpers.py b/tests/test_helpers.py index a2d22dd6..c66e650b 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -861,6 +861,20 @@ class TestStreaming(object): assert rv.data == b'Hello World!' assert called == [42] + def test_stream_keeps_session(self, app, client): + @app.route('/') + def index(): + flask.session['test'] = 'flask' + + @flask.stream_with_context + def gen(): + yield flask.session['test'] + + return flask.Response(gen()) + + rv = client.get('/') + assert rv.data == b'flask' + class TestSafeJoin(object): def test_safe_join(self):