Ejemplo n.º 1
0
    def process_handshake_header(self, headers):
        """
        Read the upgrade handshake's response headers and
        validate them against :rfc:`6455`.
        """
        protocols = []
        extensions = []

        headers = headers.strip()

        for header_line in headers.split(b'\r\n'):
            header, value = header_line.split(b':', 1)
            header = header.strip().lower()
            value = value.strip().lower()

            if header == b'upgrade' and value != b'websocket':
                raise HandshakeError("Invalid Upgrade header: %s" % value)

            elif header == b'connection' and value != b'upgrade':
                raise HandshakeError("Invalid Connection header: %s" % value)

            elif header == b'sec-websocket-accept':
                match = b64encode(sha1(self.key + WS_KEY).digest())
                if value != match.lower():
                    raise HandshakeError("Invalid challenge response: %s" %
                                         value)

            elif header == b'sec-websocket-protocol':
                protocols = [p.decode('utf8') for p in value.split(b',')]

            elif header == b'sec-websocket-extensions':
                extensions = value.split(b',')

        return protocols, extensions
 def process_response_line(self, response_line):
     """
     Ensure that we received a HTTP `101` status code in
     response to our request and if not raises :exc:`HandshakeError`.
     """
     protocol, code, status = response_line.split(b' ', 2)
     if code != b'101':
         raise HandshakeError("Invalid response status for %s: %s %s" %
                              (self.url, code, status))
Ejemplo n.º 3
0
def _send_http_connect(sock, host, port):
    connect_header = "CONNECT {0}:{1} HTTP/1.0{2}".format(
        host, port, doubleCRLF)

    sock.send(connect_header)

    code, status, _headers, _body = _read_http_response(sock)

    if code != b'200':
        raise HandshakeError("HTTP CONNECT to proxy failed: {0} {1}".format(
            code, status))

    return sock
Ejemplo n.º 4
0
def _read_http_response(sock):
    response = b''
    while True:
        bytes_ = sock.recv(128, 0)
        if not bytes_:
            break
        response += bytes_
        if doubleCRLF in response:
            break

    if not response:
        raise HandshakeError("No response")

    headers, _, body = response.partition(doubleCRLF)
    response_line, _, headers = headers.partition(b'\r\n')
    _protocol, code, status = response_line.split(b' ', 2)

    return code, status, headers, body
Ejemplo n.º 5
0
    def connect(self):
        """
        Connects this websocket and starts the upgrade handshake
        with the remote endpoint.
        """
        try:
            self.sock.settimeout(300)

            if self.scheme == "wss" and not self.proxy:
                self.sock = _ssl_wrap_socket(self.sock, self.host)
                self.sock.connect(self.bind_addr)
            elif self.scheme == "wss" and self.proxy:
                self.sock.connect(self.proxy)
                _send_http_connect(self.sock, self.host, self.port)
                self.sock = _ssl_wrap_socket(self.sock, self.host)
            else:
                self.sock.connect(self.bind_addr)

            self._write(self.handshake_request)

            try:
                code, status, headers, body = _read_http_response(self.sock)
                if code != b'101':
                    raise HandshakeError(
                        "Invalid response status for %s: %s %s" %
                        (self.url, code, status))
                self.protocols, self.extensions =\
                    self.process_handshake_header(headers)
            except HandshakeError:
                self.close_connection()
                raise

            if body:
                self.process(body)
        except Exception as e:
            logger.exception(e)
            try:
                if self.sock:
                    self.sock.close()
            except Exception:
                pass
            self.sock = None
            raise e
    def connect(self):
        """
        Connects this websocket and starts the upgrade handshake
        with the remote endpoint.
        """
        if self.scheme == "wss":

            if sys.version_info < (2, 7, 9):
                if sys.version_info >= (2, 7, 0):
                    try:
                        import backports.ssl
                    except ImportError:
                        raise RuntimeError(
                            "In order to use secure websockets with "
                            "Python 2.7.8 and earlier please install "
                            " the backports.ssl package.")
                    try:
                        import OpenSSL
                        assert OpenSSL
                    except ImportError:
                        raise RuntimeError(
                            "Please make sure PyOpenSSL >= 0.15 is installed")

                    try:
                        openssl_version = OpenSSL.__version__
                        from distutils.version import LooseVersion
                        assert LooseVersion(openssl_version) >= LooseVersion(
                            '0.15.0')
                    except Exception:
                        raise RuntimeError(
                            "Please make sure that PyOpenSSL version is"
                            "at least 0.15, found only {0}".format(
                                openssl_version))

                    ctx = backports.ssl.SSLContext(
                        backports.ssl.PROTOCOL_SSLv23)
                    ctx.verify_mode = backports.ssl.CERT_REQUIRED
                    ctx.check_hostname = True
                    ctx.ca_file = certifi.where()

                else:
                    raise RuntimeError("Python 2.6 is not supported")
            else:
                import ssl
                ctx = ssl.create_default_context(
                    purpose=ssl.Purpose.SERVER_AUTH, cafile=certifi.where())

            self.sock = ctx.wrap_socket(self.sock, server_hostname=self.host)
        assert certifi

        try:
            self.sock.settimeout(300)
            self.sock.connect(self.bind_addr)

            self._write(self.handshake_request)

            response = b''
            doubleCLRF = b'\r\n\r\n'
            while True:
                bytes_ = self.sock.recv(128, 0)
                if not bytes_:
                    break
                response += bytes_
                if doubleCLRF in response:
                    break

            if not response:
                self.close_connection()
                raise HandshakeError("No response")

            headers, _, body = response.partition(doubleCLRF)
            response_line, _, headers = headers.partition(b'\r\n')

            try:
                self.process_response_line(response_line)
                self.protocols, self.extensions =\
                    self.process_handshake_header(headers)
            except HandshakeError:
                self.close_connection()
                raise

            if body:
                self.process(body)
        except Exception as e:
            logger.exception(e)
            try:
                if self.sock:
                    self.sock.close()
            except Exception:
                pass
            self.sock = None
            raise e