Skip to content

Commit

Permalink
Do not fork the session unless it is modified
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Oct 18, 2015
1 parent be900a8 commit 26172f4
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 15 deletions.
21 changes: 12 additions & 9 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ regular HTTP request. The following list describes what works and what doesn't:
- An application context is pushed before invoking an event handler making
``current_app`` and ``g`` available to the handler.
- A request context is also pushed before invoking a handler, also making
``request`` and ``session`` available. Note that WebSocket events do not
``request`` and ``session`` available. But note that WebSocket events do not
have individual requests associated with them, so the request context that
started the connection is pushed for all the events that are dispatched
during the life of the connection.
Expand All @@ -420,14 +420,17 @@ regular HTTP request. The following list describes what works and what doesn't:
- The ``session`` context global behaves in a different way than in regular
requests. A copy of the user session at the time the SocketIO connection is
established is made available to handlers invoked in the context of that
connection. Any changes made to the session inside a SocketIO handler are
preserved, but only in the SocketIO context, these changes will not be seen
by regular HTTP handlers. The technical reason for this limitation is that to
save the user session a cookie needs to be sent to the client, and that
requires HTTP request and response, which do not exist in a socket
connection. When using server-side session storage SocketIO handlers can
update user sessions even for HTTP routes (see the
`Flask-KVsession <http://pythonhosted.org/Flask-KVSession/>`_ extension).
connection. If a SocketIO handler modifies the session, the modified session
will be preserved for future SocketIO handlers, but regular HTTP route
handlers will not see these changes. Effectively, when a SocketIO handler
modifies the session, a "fork" of the session is created exclusively for
these handlers. The technical reason for this limitation is that to save the
user session a cookie needs to be sent to the client, and that requires HTTP
request and response, which do not exist in a SocketIO connection. When
using server-side sessions such as those provided by the Flask-Session or
Flask-KVSession extensions, changes made to the session in HTTP route
handlers can be seen by SocketIO handlers, as long as the session is not
modified in the SocketIO handlers.
- The ``before_request`` and ``after_request`` hooks are not invoked for
SocketIO event handlers.
- SocketIO handlers can take custom decorators, but most Flask decorators will
Expand Down
9 changes: 5 additions & 4 deletions flask_socketio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,11 @@ def _handler(sid, *args):
raise
type, value, traceback = sys.exc_info()
return err_handler(value)
self.server.environ[sid]['saved_session'] = {}
self._copy_session(
flask.session,
self.server.environ[sid]['saved_session'])
if flask.session.modified:
self.server.environ[sid]['saved_session'] = {}
self._copy_session(
flask.session,
self.server.environ[sid]['saved_session'])
return ret
self.server.on(message, _handler, namespace=namespace)
return _handler
Expand Down
7 changes: 5 additions & 2 deletions test_socketio.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
@socketio.on('connect')
def on_connect():
send('connected')
session['a'] = 'b'


@socketio.on('disconnect')
Expand All @@ -39,6 +38,8 @@ def on_disconnect_test():
@socketio.on('message')
def on_message(message):
send(message)
if message == 'test session':
session['a'] = 'b'
if message not in "test noack":
return message

Expand Down Expand Up @@ -264,7 +265,7 @@ def test_request_event_data(self):
global request_event_data
request_event_data = None
client.emit('other custom event', 'foo')
expected_data = {'message': 'other custom event', 'args' : ('foo',)}
expected_data = {'message': 'other custom event', 'args': ('foo',)}
self.assertTrue(request_event_data == expected_data)

def test_emit_namespace(self):
Expand Down Expand Up @@ -310,6 +311,8 @@ def test_session(self):
client = socketio.test_client(app)
client.get_received()
client.send('echo this message back')
self.assertNotIn('saved_session', socketio.server.environ[client.sid])
client.send('test session')
session = socketio.server.environ[client.sid]['saved_session']
self.assertTrue(session['a'] == 'b')

Expand Down

0 comments on commit 26172f4

Please sign in to comment.