示例#1
0
def _secure(s, host, ssl_context, **config):
    local_port = s.getsockname()[1]
    # Secure the connection if an SSL context has been provided
    if ssl_context and SSL_AVAILABLE:
        log_debug("[#%04X]  C: <SECURE> %s", local_port, host)
        try:
            s = ssl_context.wrap_socket(s, server_hostname=host if HAS_SNI and host else None)
        except SSLError as cause:
            s.close()
            error = SecurityError("Failed to establish secure connection to {!r}".format(cause.args[1]))
            error.__cause__ = cause
            raise error
        else:
            # Check that the server provides a certificate
            der_encoded_server_certificate = s.getpeercert(binary_form=True)
            if der_encoded_server_certificate is None:
                s.close()
                raise ProtocolError("When using a secure socket, the server should always "
                                    "provide a certificate")
            trust = config.get("trust", TRUST_DEFAULT)
            if trust == TRUST_ON_FIRST_USE:
                store = PersonalCertificateStore()
                if not store.match_or_trust(host, der_encoded_server_certificate):
                    s.close()
                    raise ProtocolError("Server certificate does not match known certificate "
                                        "for %r; check details in file %r" % (host, KNOWN_HOSTS))
    else:
        der_encoded_server_certificate = None
    return s, der_encoded_server_certificate
示例#2
0
def _secure(s, host, ssl_context):
    local_port = s.getsockname()[1]
    # Secure the connection if an SSL context has been provided
    if ssl_context:
        log_debug("[#%04X]  C: <SECURE> %s", local_port, host)
        try:
            s = ssl_context.wrap_socket(
                s, server_hostname=host if HAS_SNI and host else None)
        except SSLError as cause:
            s.close()
            error = SecurityError(
                "Failed to establish secure connection to {!r}".format(
                    cause.args[1]))
            error.__cause__ = cause
            raise error
        else:
            # Check that the server provides a certificate
            der_encoded_server_certificate = s.getpeercert(binary_form=True)
            if der_encoded_server_certificate is None:
                s.close()
                raise ProtocolError(
                    "When using a secure socket, the server should always "
                    "provide a certificate")
    else:
        der_encoded_server_certificate = None
    return s, der_encoded_server_certificate
示例#3
0
 def run(self, statement, parameters=None, bookmarks=None, metadata=None, timeout=None, **handlers):
     if self.server.supports("statement_reuse"):
         if statement.upper() not in (u"BEGIN", u"COMMIT", u"ROLLBACK"):
             if statement == self._last_run_statement:
                 statement = ""
             else:
                 self._last_run_statement = statement
     if not parameters:
         parameters = {}
     if self.protocol_version >= 3:
         extra = {}
         if bookmarks:
             try:
                 extra["bookmarks"] = list(bookmarks)
             except TypeError:
                 raise TypeError("Bookmarks must be provided within an iterable")
         if metadata:
             try:
                 extra["tx_metadata"] = dict(metadata)
             except TypeError:
                 raise TypeError("Metadata must be coercible to a dict")
         if timeout:
             try:
                 extra["tx_timeout"] = int(1000 * timeout)
             except TypeError:
                 raise TypeError("Timeout must be specified as a number of seconds")
         fields = (statement, parameters, extra)
     else:
         if metadata:
             raise ProtocolError("Bolt v%d does not support RUN metadata" % self.protocol_version)
         fields = (statement, parameters)
     log_debug("[#%04X]  C: RUN %s", self.local_port, " ".join(map(repr, fields)))
     self._append(b"\x10", fields, Response(self, **handlers))
示例#4
0
 def _yield_messages(self, sock):
     try:
         buffer = UnpackableBuffer()
         chunk_loader = self._load_chunks(sock, buffer)
         unpacker = Unpacker(buffer)
         details = []
         while True:
             unpacker.reset()
             details[:] = ()
             chunk_size = -1
             while chunk_size != 0:
                 chunk_size = next(chunk_loader)
             summary_signature = None
             summary_metadata = None
             size, signature = unpacker.unpack_structure_header()
             if size > 1:
                 raise ProtocolError("Expected one field")
             if signature == b"\x71":
                 data = unpacker.unpack()
                 details.append(data)
             else:
                 summary_signature = signature
                 summary_metadata = unpacker.unpack_map()
             yield details, summary_signature, summary_metadata
     except OSError as error:
         self.on_error(error)
示例#5
0
    def _fetch(self):
        """ Receive at least one message from the server, if available.

        :return: 2-tuple of number of detail messages and number of summary messages fetched
        """
        if self.closed():
            raise self.Error(
                "Failed to read from closed connection {!r}".format(
                    self.server.address))
        if self.defunct():
            raise self.Error(
                "Failed to read from defunct connection {!r}".format(
                    self.server.address))
        if not self.responses:
            return 0, 0

        self._receive()

        details, summary_signature, summary_metadata = self._unpack()

        if details:
            log_debug("[#%04X]  S: RECORD * %d", self.local_port,
                      len(details))  # TODO
            self.responses[0].on_records(details)

        if summary_signature is None:
            return len(details), 0

        response = self.responses.popleft()
        response.complete = True
        if summary_signature == b"\x70":
            log_debug("[#%04X]  S: SUCCESS %r", self.local_port,
                      summary_metadata)
            response.on_success(summary_metadata or {})
        elif summary_signature == b"\x7E":
            self._last_run_statement = None
            log_debug("[#%04X]  S: IGNORED", self.local_port)
            response.on_ignored(summary_metadata or {})
        elif summary_signature == b"\x7F":
            self._last_run_statement = None
            log_debug("[#%04X]  S: FAILURE %r", self.local_port,
                      summary_metadata)
            response.on_failure(summary_metadata or {})
        else:
            self._last_run_statement = None
            raise ProtocolError(
                "Unexpected response message with signature %02X" %
                summary_signature)

        return len(details), 1
示例#6
0
    def _unpack(self):
        unpacker = self.unpacker
        input_buffer = self.input_buffer

        details = []
        summary_signature = None
        summary_metadata = None
        more = True
        while more:
            unpacker.attach(input_buffer.frame())
            size, signature = unpacker.unpack_structure_header()
            if size > 1:
                raise ProtocolError("Expected one field")
            if signature == b"\x71":
                data = unpacker.unpack_list()
                details.append(data)
                more = input_buffer.frame_message()
            else:
                summary_signature = signature
                summary_metadata = unpacker.unpack_map()
                more = False
        return details, summary_signature, summary_metadata
示例#7
0
def _handshake(s, resolved_address, der_encoded_server_certificate, **config):
    """

    :param s:
    :return:
    """
    local_port = s.getsockname()[1]

    # Send details of the protocol versions supported
    supported_versions = [3, 2, 1, 0]
    handshake = [MAGIC_PREAMBLE] + supported_versions
    log_debug("[#%04X]  C: <MAGIC> 0x%08X", local_port, MAGIC_PREAMBLE)
    log_debug("[#%04X]  C: <HANDSHAKE> 0x%08X 0x%08X 0x%08X 0x%08X",
              local_port, *supported_versions)
    data = b"".join(struct_pack(">I", num) for num in handshake)
    s.sendall(data)

    # Handle the handshake response
    ready_to_read = False
    while not ready_to_read:
        ready_to_read, _, _ = select((s, ), (), (), 1)
    try:
        data = s.recv(4)
    except (IOError, OSError):  # TODO 2.0: remove IOError alias
        raise ServiceUnavailable(
            "Failed to read any data from server {!r} after connected".format(
                resolved_address))
    data_size = len(data)
    if data_size == 0:
        # If no data is returned after a successful select
        # response, the server has closed the connection
        log_debug("[#%04X]  S: <CLOSE>", local_port)
        s.close()
        raise ServiceUnavailable(
            "Connection to %r closed without handshake response" %
            (resolved_address, ))
    if data_size != 4:
        # Some garbled data has been received
        log_debug("[#%04X]  S: @*#!", local_port)
        s.close()
        raise ProtocolError(
            "Expected four byte Bolt handshake response from %r, received %r instead; "
            "check for incorrect port number" % (resolved_address, data))
    agreed_version, = struct_unpack(">I", data)
    log_debug("[#%04X]  S: <HANDSHAKE> 0x%08X", local_port, agreed_version)
    if agreed_version == 0:
        log_debug("[#%04X]  C: <CLOSE>", local_port)
        s.shutdown(SHUT_RDWR)
        s.close()
    elif agreed_version in (1, 2):
        connection = Connection(
            agreed_version,
            resolved_address,
            s,
            der_encoded_server_certificate=der_encoded_server_certificate,
            **config)
        connection.init()
        return connection
    elif agreed_version in (3, ):
        connection = Connection(
            agreed_version,
            resolved_address,
            s,
            der_encoded_server_certificate=der_encoded_server_certificate,
            **config)
        connection.hello()
        return connection
    elif agreed_version == 0x48545450:
        log_debug("[#%04X]  S: <CLOSE>", local_port)
        s.close()
        raise ServiceUnavailable("Cannot to connect to Bolt service on {!r} "
                                 "(looks like HTTP)".format(resolved_address))
    else:
        log_debug("[#%04X]  S: <CLOSE>", local_port)
        s.close()
        raise ProtocolError(
            "Unknown Bolt protocol version: {}".format(agreed_version))
示例#8
0
 def fail(metadata):
     raise ProtocolError("RESET failed %r" % metadata)
示例#9
0
    def fetch_message(self):
        """ Receive at least one message from the server, if available.

        :return: 2-tuple of number of detail messages and number of summary
                 messages fetched
        """
        if self._closed:
            raise self.Error("Failed to read from closed connection "
                             "{!r} ({!r})".format(self.unresolved_address,
                                                  self.server.address))
        if self._defunct:
            raise self.Error("Failed to read from defunct connection "
                             "{!r} ({!r})".format(self.unresolved_address,
                                                  self.server.address))
        if not self.responses:
            return 0, 0

        # Receive exactly one message
        try:
            details, summary_signature, summary_metadata = next(self.inbox)
        except (IOError, OSError) as error:
            log.error("Failed to read data from connection "
                      "{!r} ({!r}); ({!r})".format(
                          self.unresolved_address, self.server.address,
                          "; ".join(map(repr, error.args))))
            if self.pool:
                self.pool.deactivate(self.unresolved_address)
            raise

        if details:
            log.debug("[#%04X]  S: RECORD * %d", self.local_port,
                      len(details))  # TODO
            self.responses[0].on_records(details)

        if summary_signature is None:
            return len(details), 0

        response = self.responses.popleft()
        response.complete = True
        if summary_signature == b"\x70":
            log.debug("[#%04X]  S: SUCCESS %r", self.local_port,
                      summary_metadata)
            response.on_success(summary_metadata or {})
        elif summary_signature == b"\x7E":
            log.debug("[#%04X]  S: IGNORED", self.local_port)
            response.on_ignored(summary_metadata or {})
        elif summary_signature == b"\x7F":
            log.debug("[#%04X]  S: FAILURE %r", self.local_port,
                      summary_metadata)
            try:
                response.on_failure(summary_metadata or {})
            except (ConnectionExpired, ServiceUnavailable,
                    DatabaseUnavailableError):
                if self.pool:
                    self.pool.deactivate(self.unresolved_address),
                raise
            except (NotALeaderError, ForbiddenOnReadOnlyDatabaseError):
                if self.pool:
                    self.pool.remove_writer(self.unresolved_address),
                raise
        else:
            raise ProtocolError("Unexpected response message with "
                                "signature %02X" % summary_signature)

        return len(details), 1