def handle_exception(self, exception): """ Called by the server when our application tracebacks """ if hasattr(self, "handshake_deferred"): # If the handshake is still ongoing, we need to emit a HTTP error # code rather than a WebSocket one. self.handshake_deferred.errback(ConnectionDeny(code=500, reason="Internal server error")) else: self.sendCloseFrame(code=1011)
def serverReject(self): """ Called when we get a message saying to accept the connection. """ self.handshake_deferred.errback(ConnectionDeny(code=403, reason="Access denied")) self.cleanup() logger.debug("WebSocket %s rejected by application", self.reply_channel) self.factory.log_action("websocket", "rejected", { "path": self.request.path, "client": "%s:%s" % tuple(self.client_addr) if self.client_addr else None, })
def onConnect(self, request): self.request = request self.packets_received = 0 self.protocol_to_accept = None self.socket_opened = time.time() self.last_data = time.time() try: # Sanitize and decode headers self.clean_headers = [] for name, value in request.headers.items(): name = name.encode("ascii") # Prevent CVE-2015-0219 if b"_" in name: continue self.clean_headers.append( (name.lower(), value.encode("latin1"))) # Reconstruct query string # TODO: get autobahn to provide it raw query_string = urlencode(request.params, doseq=True).encode("ascii") # Make sending channel self.reply_channel = self.main_factory.make_send_channel() # Tell main factory about it self.main_factory.reply_protocols[self.reply_channel] = self # Get client address if possible if hasattr(self.transport.getPeer(), "host") and hasattr( self.transport.getPeer(), "port"): self.client_addr = [ self.transport.getPeer().host, self.transport.getPeer().port ] self.server_addr = [ self.transport.getHost().host, self.transport.getHost().port ] else: self.client_addr = None self.server_addr = None if self.main_factory.proxy_forwarded_address_header: self.client_addr = parse_x_forwarded_for( self.http_headers, self.main_factory.proxy_forwarded_address_header, self.main_factory.proxy_forwarded_port_header, self.client_addr) # Make initial request info dict from request (we only have it here) self.path = request.path.encode("ascii") self.request_info = { "path": self.unquote(self.path), "headers": self.clean_headers, "query_string": self.unquote(query_string), "client": self.client_addr, "server": self.server_addr, "reply_channel": self.reply_channel, "order": 0, } except: # Exceptions here are not displayed right, just 500. # Turn them into an ERROR log. logger.error(traceback.format_exc()) raise ws_protocol = None for header, value in self.clean_headers: if header == b'sec-websocket-protocol': protocols = [x.strip() for x in self.unquote(value).split(",")] for protocol in protocols: if protocol in self.factory.protocols: ws_protocol = protocol break # Work out what subprotocol we will accept, if any if ws_protocol and ws_protocol in self.factory.protocols: self.protocol_to_accept = ws_protocol else: self.protocol_to_accept = None # Send over the connect message try: self.channel_layer.send("websocket.connect", self.request_info) except self.channel_layer.ChannelFull: # You have to consume websocket.connect according to the spec, # so drop the connection. self.muted = True logger.warn( "WebSocket force closed for %s due to connect backpressure", self.reply_channel) # Send code 503 "Service Unavailable" with close. raise ConnectionDeny(code=503, reason="Connection queue at capacity") else: self.factory.log_action( "websocket", "connecting", { "path": self.request.path, "client": "%s:%s" % tuple(self.client_addr) if self.client_addr else None, }) # Make a deferred and return it - we'll either call it or err it later on self.handshake_deferred = defer.Deferred() return self.handshake_deferred