Created
November 20, 2014 18:31
-
-
Save FZambia/8b4088465d0daf0387a1 to your computer and use it in GitHub Desktop.
SockJS ws ping pong
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BaseSession(object): | |
def _heartbeat(self): | |
"""Heartbeat callback""" | |
if self.handler is not None: | |
if self.server.settings.get('ws_ping_pong', False) and hasattr(self.handler, 'ping'): | |
self.handler.ping(proto.HEARTBEAT) | |
else: | |
self.handler.send_pack(proto.HEARTBEAT) | |
else: | |
self.stop_heartbeat() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from tornado import websocket, escape | |
import tornado.ioloop | |
import time | |
try: | |
from urllib.parse import urlparse # py3 | |
except ImportError: | |
from urlparse import urlparse # py2 | |
class SockJSWebSocketHandler(websocket.WebSocketHandler): | |
ping_pong_timeout = None | |
def on_ping_pong_timeout(self): | |
self.ping_pong_timeout = None | |
if self.session: | |
self.session.close() | |
print 'session closed' | |
def ping(self, data): | |
print 'sending ping' | |
if self.ping_pong_timeout: | |
print 'timeout already active - return' | |
return | |
if not self.session: | |
return | |
super(SockJSWebSocketHandler, self).ping(data) | |
ping_pong_timeout = self.session.server.settings.get( | |
'ws_ping_pong_timeout', 10 | |
) | |
self.ping_pong_timeout = tornado.ioloop.IOLoop.instance().add_timeout( | |
time.time() + ping_pong_timeout, self.on_ping_pong_timeout | |
) | |
print 'ping sent, timeout activated' | |
def on_pong(self, data): | |
print 'pong received' | |
if self.ping_pong_timeout: | |
tornado.ioloop.IOLoop.instance().remove_timeout(self.ping_pong_timeout) | |
self.ping_pong_timeout = None | |
print 'timeout deactivated' | |
def check_origin(self, origin): | |
# let tornado first check if connection from the same domain | |
same_domain = super(SockJSWebSocketHandler, self).check_origin(origin) | |
if same_domain: | |
return True | |
# this is cross-origin connection - check using SockJS server settings | |
allow_origin = self.server.settings.get("websocket_allow_origin", "*") | |
if allow_origin == "*": | |
return True | |
else: | |
parsed_origin = urlparse(origin) | |
origin = parsed_origin.netloc | |
origin = origin.lower() | |
return origin in allow_origin | |
def abort_connection(self): | |
self.ws_connection._abort() | |
def _execute(self, transforms, *args, **kwargs): | |
# Websocket only supports GET method | |
if self.request.method != "GET": | |
self.stream.write(escape.utf8( | |
"HTTP/1.1 405 Method Not Allowed\r\n" | |
"Allow: GET\r\n" | |
"Connection: Close\r\n" | |
"\r\n" | |
)) | |
self.stream.close() | |
return | |
# Upgrade header should be present and should be equal to WebSocket | |
if self.request.headers.get("Upgrade", "").lower() != "websocket": | |
self.stream.write(escape.utf8( | |
"HTTP/1.1 400 Bad Request\r\n" | |
"Connection: Close\r\n" | |
"\r\n" | |
"Can \"Upgrade\" only to \"WebSocket\"." | |
)) | |
self.stream.close() | |
return | |
# Connection header should be upgrade. Some proxy servers/load balancers | |
# might mess with it. | |
headers = self.request.headers | |
connection = map(lambda s: s.strip().lower(), headers.get("Connection", "").split(",")) | |
if "upgrade" not in connection: | |
self.stream.write(escape.utf8( | |
"HTTP/1.1 400 Bad Request\r\n" | |
"Connection: Close\r\n" | |
"\r\n" | |
"\"Connection\" must be \"Upgrade\"." | |
)) | |
self.stream.close() | |
return | |
return super(SockJSWebSocketHandler, self)._execute(transforms, *args, **kwargs) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment