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)
Exemple #2
0
 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,
     })
Exemple #3
0
    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