Fix #2935: Copy current session object in copy_current_request_context (#2936)

Add session to RequestContext.copy()
This commit is contained in:
Dave Chevell 2018-11-04 14:32:24 +11:00 committed by David Lord
parent 7e714bd28b
commit e08bcf9f97
3 changed files with 22 additions and 6 deletions

View File

@ -9,6 +9,12 @@ Version 1.1
Unreleased
- :meth:`flask.RequestContext.copy` includes the current session
object in the request context copy. This prevents ``flask.session``
pointing to an out-of-date object. (`#2935`)
.. _#2935: https://github.com/pallets/flask/issues/2935
Version 1.0.3
-------------

View File

@ -122,7 +122,8 @@ def copy_current_request_context(f):
"""A helper function that decorates a function to retain the current
request context. This is useful when working with greenlets. The moment
the function is decorated a copy of the request context is created and
then pushed when the function is called.
then pushed when the function is called. The current session is also
included in the copied request context.
Example::
@ -133,8 +134,8 @@ def copy_current_request_context(f):
def index():
@copy_current_request_context
def do_some_work():
# do some work here, it can access flask.request like you
# would otherwise in the view function.
# do some work here, it can access flask.request or
# flask.session like you would otherwise in the view function.
...
gevent.spawn(do_some_work)
return 'Regular response'
@ -276,14 +277,14 @@ class RequestContext(object):
that situation, otherwise your unittests will leak memory.
"""
def __init__(self, app, environ, request=None):
def __init__(self, app, environ, request=None, session=None):
self.app = app
if request is None:
request = app.request_class(environ)
self.request = request
self.url_adapter = app.create_url_adapter(self.request)
self.flashes = None
self.session = None
self.session = session
# Request contexts can be pushed multiple times and interleaved with
# other request contexts. Now only if the last level is popped we
@ -321,10 +322,15 @@ class RequestContext(object):
request object is locked.
.. versionadded:: 0.10
.. versionchanged:: 1.1
The current session object is used instead of reloading the original
data. This prevents `flask.session` pointing to an out-of-date object.
"""
return self.__class__(self.app,
environ=self.request.environ,
request=self.request
request=self.request,
session=self.session
)
def match_request(self):

View File

@ -156,6 +156,7 @@ class TestGreenletContextCopying(object):
@app.route('/')
def index():
flask.session['fizz'] = 'buzz'
reqctx = flask._request_ctx_stack.top.copy()
def g():
@ -166,6 +167,7 @@ class TestGreenletContextCopying(object):
assert flask.current_app == app
assert flask.request.path == '/'
assert flask.request.args['foo'] == 'bar'
assert flask.session.get('fizz') == 'buzz'
assert not flask.request
return 42
@ -183,6 +185,7 @@ class TestGreenletContextCopying(object):
@app.route('/')
def index():
flask.session['fizz'] = 'buzz'
reqctx = flask._request_ctx_stack.top.copy()
@flask.copy_current_request_context
@ -191,6 +194,7 @@ class TestGreenletContextCopying(object):
assert flask.current_app == app
assert flask.request.path == '/'
assert flask.request.args['foo'] == 'bar'
assert flask.session.get('fizz') == 'buzz'
return 42
greenlets.append(greenlet(g))