Skip to content

Commit e08bcf9

Browse files
dchevelldavidism
authored andcommitted
Fix pallets#2935: Copy current session object in copy_current_request_context (pallets#2936)
Add session to RequestContext.copy()
1 parent 7e714bd commit e08bcf9

File tree

3 files changed

+22
-6
lines changed

3 files changed

+22
-6
lines changed

CHANGES.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ Version 1.1
99

1010
Unreleased
1111

12+
- :meth:`flask.RequestContext.copy` includes the current session
13+
object in the request context copy. This prevents ``flask.session``
14+
pointing to an out-of-date object. (`#2935`)
15+
16+
.. _#2935: https://github.com/pallets/flask/issues/2935
17+
1218

1319
Version 1.0.3
1420
-------------

flask/ctx.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ def copy_current_request_context(f):
122122
"""A helper function that decorates a function to retain the current
123123
request context. This is useful when working with greenlets. The moment
124124
the function is decorated a copy of the request context is created and
125-
then pushed when the function is called.
125+
then pushed when the function is called. The current session is also
126+
included in the copied request context.
126127
127128
Example::
128129
@@ -133,8 +134,8 @@ def copy_current_request_context(f):
133134
def index():
134135
@copy_current_request_context
135136
def do_some_work():
136-
# do some work here, it can access flask.request like you
137-
# would otherwise in the view function.
137+
# do some work here, it can access flask.request or
138+
# flask.session like you would otherwise in the view function.
138139
...
139140
gevent.spawn(do_some_work)
140141
return 'Regular response'
@@ -276,14 +277,14 @@ class RequestContext(object):
276277
that situation, otherwise your unittests will leak memory.
277278
"""
278279

279-
def __init__(self, app, environ, request=None):
280+
def __init__(self, app, environ, request=None, session=None):
280281
self.app = app
281282
if request is None:
282283
request = app.request_class(environ)
283284
self.request = request
284285
self.url_adapter = app.create_url_adapter(self.request)
285286
self.flashes = None
286-
self.session = None
287+
self.session = session
287288

288289
# Request contexts can be pushed multiple times and interleaved with
289290
# other request contexts. Now only if the last level is popped we
@@ -321,10 +322,15 @@ def copy(self):
321322
request object is locked.
322323
323324
.. versionadded:: 0.10
325+
326+
.. versionchanged:: 1.1
327+
The current session object is used instead of reloading the original
328+
data. This prevents `flask.session` pointing to an out-of-date object.
324329
"""
325330
return self.__class__(self.app,
326331
environ=self.request.environ,
327-
request=self.request
332+
request=self.request,
333+
session=self.session
328334
)
329335

330336
def match_request(self):

tests/test_reqctx.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ def test_greenlet_context_copying(self, app, client):
156156

157157
@app.route('/')
158158
def index():
159+
flask.session['fizz'] = 'buzz'
159160
reqctx = flask._request_ctx_stack.top.copy()
160161

161162
def g():
@@ -166,6 +167,7 @@ def g():
166167
assert flask.current_app == app
167168
assert flask.request.path == '/'
168169
assert flask.request.args['foo'] == 'bar'
170+
assert flask.session.get('fizz') == 'buzz'
169171
assert not flask.request
170172
return 42
171173

@@ -183,6 +185,7 @@ def test_greenlet_context_copying_api(self, app, client):
183185

184186
@app.route('/')
185187
def index():
188+
flask.session['fizz'] = 'buzz'
186189
reqctx = flask._request_ctx_stack.top.copy()
187190

188191
@flask.copy_current_request_context
@@ -191,6 +194,7 @@ def g():
191194
assert flask.current_app == app
192195
assert flask.request.path == '/'
193196
assert flask.request.args['foo'] == 'bar'
197+
assert flask.session.get('fizz') == 'buzz'
194198
return 42
195199

196200
greenlets.append(greenlet(g))

0 commit comments

Comments
 (0)