def upgrade_websocket(self, environ, start_response): """ Attempt to upgrade the socket environ['wsgi.input'] into a websocket enabled connection. """ websocket_version = environ.get("HTTP_SEC_WEBSOCKET_VERSION", "") if not websocket_version: raise UpgradeRequiredError elif websocket_version not in self.WS_VERSIONS: raise HandshakeError("Unsupported WebSocket Version: {0}".format(websocket_version)) key = environ.get("HTTP_SEC_WEBSOCKET_KEY", "").strip() if not key: raise HandshakeError("Sec-WebSocket-Key header is missing/empty") try: key_len = len(base64.b64decode(key)) except TypeError: raise HandshakeError("Invalid key: {0}".format(key)) if key_len != 16: # 5.2.1 (3) raise HandshakeError("Invalid key: {0}".format(key)) headers = [ ("Upgrade", "websocket"), ("Connection", "Upgrade"), ("Sec-WebSocket-Accept", base64.b64encode(sha1(key + self.WS_GUID).digest())), ("Sec-WebSocket-Version", str(websocket_version)), ] logger.debug("WebSocket request accepted, switching protocols") start_response(force_str("101 Switching Protocols"), headers) start_response.im_self.finish_content() return WebSocket(environ["wsgi.input"])
def read_frame(self): """ Block until a full frame has been read from the socket. This is an internal method as calling this will not cleanup correctly if an exception is called. Use `receive` instead. :return: The header and payload as a tuple. """ header = Header.decode_header(self.stream) if header.flags: raise WebSocketError if not header.length: return header, '' try: payload = self.stream.read(header.length) except socket_error: payload = '' except Exception: logger.debug("{}: {}".format(type(e), six.text_type(e))) payload = '' if len(payload) != header.length: raise WebSocketError('Unexpected EOF reading frame payload') if header.mask: payload = header.unmask_payload(payload) return header, payload
def upgrade_websocket(self, environ, start_response): """ Attempt to upgrade the socket environ['wsgi.input'] into a websocket enabled connection. """ websocket_version = environ.get('HTTP_SEC_WEBSOCKET_VERSION', '') if not websocket_version: raise UpgradeRequiredError elif websocket_version not in self.WS_VERSIONS: raise HandshakeError('Unsupported WebSocket Version: {0}'.format(websocket_version)) key = environ.get('HTTP_SEC_WEBSOCKET_KEY', '').strip() if not key: raise HandshakeError('Sec-WebSocket-Key header is missing/empty') try: key_len = len(base64.b64decode(key)) except TypeError: raise HandshakeError('Invalid key: {0}'.format(key)) if key_len != 16: # 5.2.1 (3) raise HandshakeError('Invalid key: {0}'.format(key)) sec_ws_accept = base64.b64encode(sha1(key.encode('latin-1') + self.WS_GUID).digest()) sec_ws_accept = sec_ws_accept.decode('ascii') headers = [ ('Upgrade', 'websocket'), ('Connection', 'Upgrade'), ('Sec-WebSocket-Accept', sec_ws_accept), ('Sec-WebSocket-Version', str(websocket_version)), ] logger.debug('WebSocket request accepted, switching protocols') start_response(force_str('101 Switching Protocols'), headers) start_response.__self__.finish_content() return WebSocket(environ['wsgi.input'])
def upgrade_websocket(self, environ, start_response): """ Attempt to upgrade the socket environ['wsgi.input'] into a websocket enabled connection. """ websocket_version = environ.get('HTTP_SEC_WEBSOCKET_VERSION', '') if not websocket_version: raise UpgradeRequiredError elif websocket_version not in self.WS_VERSIONS: raise HandshakeError( 'Unsupported WebSocket Version: {0}'.format(websocket_version)) key = environ.get('HTTP_SEC_WEBSOCKET_KEY', '').strip() if not key: raise HandshakeError('Sec-WebSocket-Key header is missing/empty') try: key_len = len(base64.b64decode(key)) except TypeError: raise HandshakeError('Invalid key: {0}'.format(key)) if key_len != 16: # 5.2.1 (3) raise HandshakeError('Invalid key: {0}'.format(key)) headers = [ ('Upgrade', 'websocket'), ('Connection', 'Upgrade'), ('Sec-WebSocket-Accept', base64.b64encode(sha1(key + self.WS_GUID).digest())), ('Sec-WebSocket-Version', str(websocket_version)), ] logger.debug('WebSocket request accepted, switching protocols') start_response(force_str('101 Switching Protocols'), headers) start_response.im_self.finish_content() return WebSocket(environ['wsgi.input'])
def __call__(self, environ, start_response): """ Hijack the main loop from the original thread and listen on events on Redis and Websockets""" websocket = None redis_context = self.redis_context() try: self.assure_protocol_requirements(environ) request = WSGIRequest(environ) self.process_request(request) channels = self.process_subscriptions(request) websocket = self.upgrade_websocket(environ, start_response) logger.debug('Subscribed to channels: {0}'.format(', '.join(channels))) redis_context.subscribe_channels(request, channels) websocket_fd = websocket.get_file_descriptor() redis_fd = redis_context.get_file_descriptor() while websocket and not websocket.closed: ready = self.select([websocket_fd, redis_fd], [], [])[0] for fd in ready: if fd == websocket_fd: message = websocket.receive() redis_context.publish_message(message) elif fd == redis_fd: response = redis_context.parse_response() if response[0] == 'message': message = response[2] websocket.send(message) else: logger.error('Invalid file descriptor: {0}'.format(fd)) except WebSocketError, excpt: logger.warning('WebSocketError: ', exc_info=sys.exc_info()) response = HttpResponse(status=1001, content='Websocket Closed')
def home(request): args = [] path = 'herehaspolice/base.html' if request.method == 'POST': logger.debug("insert latlon information into DB") lat = request.POST.get('lat') lon = request.POST.get('lon') text = request.POST.get('text') logger.debug("lat=%s" % lat) logger.debug("lon=%s" % lon) logger.debug("text=%s" % text) GeoInfo.objects.create(lat=lat, lon=lon, text=text) args = {'title' : 'Police Here!!', } elif request.method == 'GET': #display main page args = {'title' : 'Police Here!!', } return render_to_response( path, args, context_instance=RequestContext(request) )
def close(self, code=1000, message=''): """ Close the websocket and connection, sending the specified code and message. The underlying socket object is _not_ closed, that is the responsibility of the initiator. """ try: message = self._encode_bytes(message) self.send_frame(struct.pack('!H%ds' % len(message), code, message), opcode=self.OPCODE_CLOSE) except WebSocketError: # Failed to write the closing frame but it's ok because we're # closing the socket anyway. logger.debug("Failed to write closing frame -> closing socket") finally: logger.debug("Closed WebSocket") self._closed = True self.stream = None
def close(self, code=1000, message=''): """ Close the websocket and connection, sending the specified code and message. The underlying socket object is _not_ closed, that is the responsibility of the initiator. """ try: message = self._encode_bytes(message) self.send_frame( struct.pack('!H%ds' % len(message), code, message), opcode=self.OPCODE_CLOSE) except WebSocketError: # Failed to write the closing frame but it's ok because we're # closing the socket anyway. logger.debug("Failed to write closing frame -> closing socket") finally: logger.debug("Closed WebSocket") self._closed = True self.stream = None
def __call__(self, environ, start_response): """ Hijack the main loop from the original thread and listen on events on Redis and Websockets""" websocket = None subscriber = self.Subscriber(self._redis_connection) try: self.assure_protocol_requirements(environ) request = WSGIRequest(environ) self.process_request(request) channels = self.process_subscriptions(request) websocket = self.upgrade_websocket(environ, start_response) logger.debug('Subscribed to channels: {0}'.format( ', '.join(channels))) subscriber.set_pubsub_channels(request, channels) websocket_fd = websocket.get_file_descriptor() listening_fds = [websocket_fd] redis_fd = subscriber.get_file_descriptor() if redis_fd: listening_fds.append(redis_fd) subscriber.send_persited_messages(websocket) while websocket and not websocket.closed: ready = self.select(listening_fds, [], [], 4.0)[0] if not ready: # flush empty socket websocket.flush() for fd in ready: if fd == websocket_fd: message = websocket.receive() if message != redis_settings.WS4REDIS_HEARTBEAT: subscriber.publish_message(message) elif fd == redis_fd: response = subscriber.parse_response() if response[0] == 'message': message = response[2] websocket.send(message) else: logger.error('Invalid file descriptor: {0}'.format(fd)) if redis_settings.WS4REDIS_HEARTBEAT: websocket.send(redis_settings.WS4REDIS_HEARTBEAT) except WebSocketError, excpt: logger.warning('WebSocketError: ', exc_info=sys.exc_info()) response = HttpResponse(status=1001, content='Websocket Closed')
def __call__(self, environ, start_response): """ Hijack the main loop from the original thread and listen on events on Redis and Websockets""" websocket = None subscriber = self.Subscriber(self._redis_connection) try: self.assure_protocol_requirements(environ) request = WSGIRequest(environ) self.process_request(request) channels = self.process_subscriptions(request) websocket = self.upgrade_websocket(environ, start_response) logger.debug('Subscribed to channels: {0}'.format(', '.join(channels))) subscriber.set_pubsub_channels(request, channels) websocket_fd = websocket.get_file_descriptor() listening_fds = [websocket_fd] redis_fd = subscriber.get_file_descriptor() if redis_fd: listening_fds.append(redis_fd) subscriber.send_persited_messages(websocket) while websocket and not websocket.closed: ready = self.select(listening_fds, [], [], 4.0)[0] if not ready: # flush empty socket websocket.flush() for fd in ready: if fd == websocket_fd: message = websocket.receive() if message != redis_settings.WS4REDIS_HEARTBEAT: subscriber.publish_message(message) elif fd == redis_fd: response = subscriber.parse_response() if response[0] == 'message': message = response[2] websocket.send(message) else: logger.error('Invalid file descriptor: {0}'.format(fd)) if redis_settings.WS4REDIS_HEARTBEAT: websocket.send(redis_settings.WS4REDIS_HEARTBEAT) except WebSocketError, excpt: logger.warning('WebSocketError: ', exc_info=sys.exc_info()) response = HttpResponse(status=1001, content='Websocket Closed')
def __call__(self, environ, start_response): """ Hijack the main loop from the original thread and listen on events on Redis and Websockets""" websocket = None request = None subscriber = self.Subscriber(self._redis_connection) try: self.assure_protocol_requirements(environ) request = WSGIRequest(environ) self.process_request(request) channels, echo_message = self.process_subscriptions(request) if callable(private_settings.WS4REDIS_ALLOWED_CHANNELS): channels = list(private_settings.WS4REDIS_ALLOWED_CHANNELS(request, channels)) websocket = self.upgrade_websocket(environ, start_response) logger.debug('Subscribed to channels: {0}'.format(', '.join(channels))) subscriber.set_pubsub_channels(request, channels) subscriber.user_connect(request) websocket_fd = websocket.get_file_descriptor() listening_fds = [websocket_fd] redis_fd = subscriber.get_file_descriptor() if redis_fd: listening_fds.append(redis_fd) subscriber.send_persited_messages(websocket) recvmsg = None while websocket and not websocket.closed: ready = self.select(listening_fds, [], [], 4.0)[0] if not ready: # flush empty socket websocket.flush() for fd in ready: if fd == websocket_fd: recvmsg = RedisMessage(websocket.receive()) if recvmsg: subscriber.publish_message(recvmsg) elif fd == redis_fd: sendmsg = RedisMessage(subscriber.parse_response()) if sendmsg and (echo_message or sendmsg != recvmsg): websocket.send(sendmsg) else: logger.error('Invalid file descriptor: {0}'.format(fd)) if private_settings.WS4REDIS_HEARTBEAT: websocket.send(private_settings.WS4REDIS_HEARTBEAT) except WebSocketError as excpt: logger.warning('WebSocketError: ', exc_info=sys.exc_info()) response = http.HttpResponse(status=1001, content='Websocket Closed') except UpgradeRequiredError as excpt: logger.info('Websocket upgrade required') response = http.HttpResponseBadRequest(status=426, content=excpt) except HandshakeError as excpt: logger.warning('HandshakeError: ', exc_info=sys.exc_info()) response = http.HttpResponseBadRequest(content=excpt) except PermissionDenied as excpt: logger.warning('PermissionDenied: ', exc_info=sys.exc_info()) response = http.HttpResponseForbidden(content=excpt) except Exception as excpt: logger.error('Other Exception: ', exc_info=sys.exc_info()) response = http.HttpResponseServerError(content=excpt) else: response = http.HttpResponse() if websocket: subscriber.user_disconnect(request) websocket.close(code=1001, message='Websocket Closed') if hasattr(start_response, 'im_self') and not start_response.im_self.headers_sent: logger.warning('Staring late response on websocket') status_text = STATUS_CODE_TEXT.get(response.status_code, 'UNKNOWN STATUS CODE') status = '{0} {1}'.format(response.status_code, status_text) start_response(force_str(status), response._headers.values()) logger.info('Finish long living response with status code: '.format(response.status_code)) return response
def __call__(self, environ, start_response): """ Hijack the main loop from the original thread and listen on events on the Redis and the Websocket filedescriptors. """ websocket = None subscriber = self.Subscriber(self._redis_connection) try: self.assure_protocol_requirements(environ) request = WSGIRequest(environ) if callable(private_settings.WS4REDIS_PROCESS_REQUEST): private_settings.WS4REDIS_PROCESS_REQUEST(request) else: self.process_request(request) channels, echo_message = self.process_subscriptions(request) if callable(private_settings.WS4REDIS_ALLOWED_CHANNELS): channels = list(private_settings.WS4REDIS_ALLOWED_CHANNELS(request, channels)) websocket = self.upgrade_websocket(environ, start_response) logger.debug('Subscribed to channels: {0}'.format(', '.join(channels))) subscriber.set_pubsub_channels(request, channels) websocket_fd = websocket.get_file_descriptor() listening_fds = [websocket_fd] redis_fd = subscriber.get_file_descriptor() if redis_fd: listening_fds.append(redis_fd) subscriber.send_persited_messages(websocket) recvmsg = None while websocket and not websocket.closed: ready = self.select(listening_fds, [], [], 4.0)[0] if not ready: # flush empty socket websocket.flush() for fd in ready: if fd == websocket_fd: recvmsg = RedisMessage(websocket.receive()) if recvmsg: subscriber.publish_message(recvmsg) elif fd == redis_fd: sendmsg = RedisMessage(subscriber.parse_response()) if sendmsg and (echo_message or sendmsg != recvmsg): websocket.send(sendmsg) else: logger.error('Invalid file descriptor: {0}'.format(fd)) # Check again that the websocket is closed before sending the heartbeat, # because the websocket can closed previously in the loop. if private_settings.WS4REDIS_HEARTBEAT and not websocket.closed: websocket.send(private_settings.WS4REDIS_HEARTBEAT) except WebSocketError as excpt: logger.warning('WebSocketError: {}'.format(excpt), exc_info=sys.exc_info()) response = http.HttpResponse(status=1001, content='Websocket Closed') except UpgradeRequiredError as excpt: logger.info('Websocket upgrade required') response = http.HttpResponseBadRequest(status=426, content=excpt) except HandshakeError as excpt: logger.warning('HandshakeError: {}'.format(excpt), exc_info=sys.exc_info()) response = http.HttpResponseBadRequest(content=excpt) except PermissionDenied as excpt: logger.warning('PermissionDenied: {}'.format(excpt), exc_info=sys.exc_info()) response = http.HttpResponseForbidden(content=excpt) except Exception as excpt: logger.error('Other Exception: {}'.format(excpt), exc_info=sys.exc_info()) response = http.HttpResponseServerError(content=excpt) else: response = http.HttpResponse() finally: subscriber.release() if websocket: websocket.close(code=1001, message='Websocket Closed') else: logger.warning('Starting late response on websocket') status_text = http_client.responses.get(response.status_code, 'UNKNOWN STATUS CODE') status = '{0} {1}'.format(response.status_code, status_text) headers = response._headers.values() if six.PY3: headers = list(headers) start_response(force_str(status), headers) logger.info('Finish non-websocket response with status code: {}'.format(response.status_code)) return response
def __call__(self, environ, start_response): """ Hijack the main loop from the original thread and listen on events on the Redis and the Websocket filedescriptors. """ websocket = None subscriber = self.Subscriber(self._redis_connection) try: self.assure_protocol_requirements(environ) request = WSGIRequest(environ) if callable(private_settings.WS4REDIS_PROCESS_REQUEST): private_settings.WS4REDIS_PROCESS_REQUEST(request) else: self.process_request(request) channels, echo_message = self.process_subscriptions(request) if callable(private_settings.WS4REDIS_ALLOWED_CHANNELS): channels = list(private_settings.WS4REDIS_ALLOWED_CHANNELS(request, channels)) websocket = self.upgrade_websocket(environ, start_response) logger.debug('Subscribed to channels: {0}'.format(', '.join(channels))) subscriber.set_pubsub_channels(request, channels) websocket_fd = websocket.get_file_descriptor() listening_fds = [websocket_fd] redis_fd = subscriber.get_file_descriptor() if redis_fd: listening_fds.append(redis_fd) subscriber.send_persited_messages(websocket) recvmsg = None while websocket and not websocket.closed: ready = self.select(listening_fds, [], [], 4.0)[0] if not ready: # flush empty socket websocket.flush() for fd in ready: if fd == websocket_fd: recvmsg = RedisMessage(websocket.receive()) if recvmsg: subscriber.publish_message(recvmsg) elif fd == redis_fd: sendmsg = RedisMessage(subscriber.parse_response()) if sendmsg and (echo_message or sendmsg != recvmsg): websocket.send(sendmsg) else: logger.error('Invalid file descriptor: {0}'.format(fd)) if private_settings.WS4REDIS_HEARTBEAT: websocket.send(private_settings.WS4REDIS_HEARTBEAT) except WebSocketError as excpt: logger.warning('WebSocketError: {}'.format(excpt), exc_info=sys.exc_info()) response = http.HttpResponse(status=1001, content='Websocket Closed') except UpgradeRequiredError as excpt: logger.info('Websocket upgrade required') response = http.HttpResponseBadRequest(status=426, content=excpt) except HandshakeError as excpt: logger.warning('HandshakeError: {}'.format(excpt), exc_info=sys.exc_info()) response = http.HttpResponseBadRequest(content=excpt) except PermissionDenied as excpt: logger.warning('PermissionDenied: {}'.format(excpt), exc_info=sys.exc_info()) response = http.HttpResponseForbidden(content=excpt) except Exception as excpt: logger.error('Other Exception: {}'.format(excpt), exc_info=sys.exc_info()) response = http.HttpResponseServerError(content=excpt) else: response = http.HttpResponse() finally: subscriber.release() if websocket: websocket.close(code=1001, message='Websocket Closed') else: logger.warning('Starting late response on websocket') status_text = STATUS_CODE_TEXT.get(response.status_code, 'UNKNOWN STATUS CODE') status = '{0} {1}'.format(response.status_code, status_text) start_response(force_str(status), response._headers.values()) logger.info('Finish non-websocket response with status code: {}'.format(response.status_code)) return response